Compare commits

..
1061 Commits
Author SHA1 Message Date
Francisco Ryan Tolmasky I 80097ea2a2 Merge branch 'master' into @each 2010-11-03 21:28:10 -07:00
Ross Boucher b85e9d83b8 Fix for the fix for extensionless IB resource names. 2010-11-03 11:18:37 -07:00
Francisco Ryan Tolmasky I 2e9684e9a7 Fix for bottom corner view of CPScrollView being broken in CPCoding circumstances (normal coding, nib2cibing, Atlas, etc.).
Reviewed by me.
2010-11-03 10:37:51 -07:00
Klaas Pieter Annema a80a0d0a13 Complete the style fix started in previous commit 2010-11-03 14:13:55 +01:00
Francisco Ryan Tolmasky I 885eff1f9b Style fix.
Reviewed by me.
2010-11-03 01:34:54 -07:00
Francisco Ryan Tolmasky I 706e80362d Slight change to last commit, change == to ===.
Reviewed by me.
2010-11-03 01:25:08 -07:00
Brian DonovanandFrancisco Ryan Tolmasky I 7bf2297125 -[CPArrayController setContent:] would interpret nil as [nil].
When initializing a CPArrayController with a value that is not an array setContent: would make it an array by replacing value with [value]. This is consistent with how Cocoa does it, but it should first check to make sure that the content is not nil. If it is, the sensible thing to do (and what Cocoa does) is to replace it with an empty array.

This commit also includes a missing import to make CPArrayControllerTest run without error.
2010-11-03 01:24:38 -07:00
Francisco Ryan Tolmasky I 99c1d18d95 Fix for targets and actions not working in nib2cibed toolbars.
Reviewed by me.
2010-11-03 00:36:30 -07:00
Ross Boucher a45668e7cb Updates to make nib2cib work better with CPToolbar (and with image resources in IB in general). 2010-11-02 20:31:43 -07:00
Francisco Ryan Tolmasky I f46bbf83a8 Slight fix for correctness with --include.
Reviewed by me.
2010-11-01 11:26:59 -07:00
Francisco Ryan Tolmasky I 52f7844aee Made it so .h files are automatically included in AppKit (avoiding needing to manually include Platform.h, etc.).
Also changed a bunch of <AppKit/*> imports to "*" imports.

Reviewed by me.
2010-11-01 11:10:01 -07:00
Klaas Pieter Annema 64aeea0f08 Merge branch 'runtime-theming' 2010-11-01 14:04:22 +01:00
Alexander Ljungberg 06db60d7df Merge branch 'fix-cptabview-not-resizable' of http://github.com/primalmotion/cappuccino into primalmotion-fix-cptabview-not-resizable 2010-10-29 16:13:47 -03:00
Alexander Ljungberg eb39e2e81a Optimise token field redraws when adding or deleting tokens by recycling token fields. This eliminates the flicker of all previous tokens whenever a new token was added. 2010-10-29 14:40:46 -03:00
Alexander Ljungberg 0867ccdc73 Reduced token height by 1 pixel to put some more whitespace underneath it in a standard height token field. 2010-10-29 14:23:36 -03:00
Antoine Mercadal 8ead5f63da fix CPtabViewTest 2010-10-28 11:01:38 +02:00
Alexander Ljungberg a80732f13a Whitespace and style cleanup. 2010-10-27 20:44:55 -03:00
Alexander Ljungberg 923d7c63b5 Fixed an accidental global. 2010-10-27 20:24:05 -03:00
Alexander Ljungberg 7626af00e7 Apply Cappuccino code style. 2010-10-27 20:16:14 -03:00
Alexander Ljungberg 1d647fab10 Merge branch 'CPPredicate-parsing' of http://github.com/cacaodev/cappuccino into cacaodev-CPPredicate-parsing 2010-10-27 19:34:44 -03:00
Alexander Ljungberg c9fcbe0e93 Merge branch 'eventualbuddha-sprintf-format-parameter-indexes' 2010-10-27 19:26:51 -03:00
Alexander Ljungberg 6d9d443d0a Merge branch 'sprintf-format-parameter-indexes' of http://github.com/eventualbuddha/cappuccino into eventualbuddha-sprintf-format-parameter-indexes 2010-10-27 19:16:50 -03:00
cacaodev 2a95523577 CPPredicate & CPExpression changes:
Parsing: fixed typos in built-in function names, fixed support for [FIRST], [LAST], [INDEX]
	Fixed aggregates {exp1,exp2}
Fixed -expressionForFunction:selectorName:arguments:
built-in functions are now class methods
Cleaned a lot of code in built-in functions
EvaluatedObjectExpression is now a singleton
Merged inserset/minus/union Set into one file
Deleted unused expression subclasses : expression_operator and expression_assignement
Added CPCoding methods and changed key names to match Cocoa
Made KeyPathExpresion a subclass of FunctionExpression like in Cocoa
Tests
2010-10-27 00:57:31 +02:00
Klaas Pieter Annema 0fa149b74f encode and decode themeClass
This makes it possible to theme any themeClass without having to subclass a CPView and return something different from defaultThemeClass. Theme a custom theme class by assigning to a control within the theme descriptor ([control setThemeClass:"your-theme-class"]).
2010-10-26 20:41:56 +02:00
Klaas Pieter Annema c7fdad883a add deprecation warning for class that have themeClass implemented 2010-10-25 16:14:33 +02:00
Klaas Pieter Annema 6e9f82212b rename CPView +themeClass to +defaultThemeClass 2010-10-25 14:15:22 +02:00
Klaas Pieter Annema 22e2bdcd25 make theme class runtime configurable 2010-10-25 13:54:39 +02:00
Klaas Pieter Annema 85c9ca518f lint cleanup in CPView 2010-10-25 13:54:19 +02:00
Alexander Ljungberg 29a93b20f4 Merge branch 'flllow-tokenfield-improvements' 2010-10-23 20:53:34 -03:00
Alexander Ljungberg b95bdca2a3 Lint cleanup. 2010-10-23 20:47:11 -03:00
Alexander Ljungberg 6fd5f66a15 Support forward delete in token fields. 2010-10-23 20:42:01 -03:00
Alexander Ljungberg 9e235f7236 Fixed: clicking tokens in a token field could disable its keyboard handling due to the input field losing focus. 2010-10-23 20:21:02 -03:00
Alexander Ljungberg 90d12ef77e Place the cursor correctly when arrow keys are used with one or more tokens selected. Fixed: the layout would not update to remove the gap for the editor if between tokens when resigning first responders. 2010-10-23 19:31:08 -03:00
Alexander Ljungberg 0c2301766a Place the cursor after the last inserted token when editing. 2010-10-23 17:09:46 -03:00
Alexander Ljungberg 8a7b6054ef If the text editing part of the token field is the last in the line, make it take up the remaining field width so that it captures clicks there. 2010-10-23 16:58:02 -03:00
Alexander Ljungberg 7037151bfc Fixed: clicking a token would cause the token field to resign first responder status, only to reclaim it on mouse up.
This was caused by the framework's stop DOM event code blurring the field. Now simply refuse to resign first responder status between mouse down and mouse up. Note that this fixes the bug the previous commit did too, but that commit improves other scrolling behaviour so it gets to stay.
2010-10-23 16:00:45 -03:00
Alexander Ljungberg ba26b19567 Fixed: if the token field was scrolled up and a token was clicked, the scroll position would jump back down. 2010-10-23 15:41:41 -03:00
Alexander Ljungberg 6587014014 Improve token field scrolling behaviour and performance: only resize the document view frame when necessary to prevent the loss of scroll position and display jumps. Fixed: if a token on a new line was clicked, the view would scroll up to the first line. 2010-10-23 14:36:42 -03:00
Alexander Ljungberg 80b16ae9ab Bluer selected tokens in token field. 2010-10-23 14:07:46 -03:00
Alexander Ljungberg 07330a0ca8 Select tokens by clicking on them. Select multiple tokens by holding down shift. Also fixed a bug when deleting multiple tokens at a time. 2010-10-23 13:49:36 -03:00
cacaodev c735399ca5 CPPredicate: Fix for fail when parsing empty quotes. With Tests. 2010-10-23 09:26:12 +02:00
Alexander Ljungberg d68f4359ac Reduce token shifting when a token is selected. Ideally there shouldn't be any shifting at all, but placing a tiny editor at the right spot simplifies scroll handling. 2010-10-23 00:22:40 -03:00
Alexander Ljungberg d4cfa4b24f Minor optimisations and cleanup. 2010-10-23 00:00:00 -03:00
Alexander Ljungberg 2912acb4f5 Simplify: remove _selectedTokenIndexes since we now have _selectedRange. Hide the editor when tokens are selected. Preserve cursor position when tokens are deleted. 2010-10-22 23:45:48 -03:00
Alexander Ljungberg 85683d8f18 Navigate among tokens with the arrow keys. Insert and delete tokens relative to the cursor. 2010-10-22 20:43:40 -03:00
Brian Donovan 8ca2a1bf5b IE uses an empty string as the value of an empty capture group. 2010-10-22 14:41:31 -07:00
Brian Donovan 8427697a4b Fix accidental globals. 2010-10-22 14:15:22 -07:00
cacaodev 275f89a340 CPPredicate: parsing 'BETWEEN' or 'CONTAINS' keywords now generates predicates with their corresponding operators. Some code style.
CPComparisonPredicate: fixed typo in 'between' operator evaluation, simplified 'contains' and 'in'  evaluation.
Added tests in CPPredicateTest for theses fixes.
2010-10-22 22:13:57 +02:00
Klaas Pieter Annema 49c8a02b5f cleanup in CPSplitView and the Aristo ThemeDescriptors 2010-10-22 13:55:37 +02:00
Klaas Pieter Annema 1165e569d2 make splitview pane divider color theme-able 2010-10-22 13:54:39 +02:00
Alexander Ljungberg e66f22d094 Allow the editor to be placed anywhere based on a selection range. 2010-10-21 23:46:03 -03:00
Alexander Ljungberg d0b29fd38c Fix resizing and initial sizing of token fields. 2010-10-21 17:49:41 -03:00
Alexander Ljungberg 28378ff19b Minor performance tweaks. 2010-10-21 17:11:47 -03:00
Alexander Ljungberg b4f2f15698 Fixed: if a token field had many tokens and a long token name was entered, that token name had to be edited in the small amount of space left on the right hand side of the token field. Now the editor wraps to a new line as needed. 2010-10-21 17:04:09 -03:00
Alexander Ljungberg 2210c1f4c5 Implemented token field overflow support as in Cocoa: if more tokens than can fit are entered, they wrap to a new line. If the new line does not fit within the height of the token field, the previous line is scrolled out of view.
Note: this replaces the previous non Cocoa behaviour where the token field would grow height-wise with new tokens. This behaviour can still be useful, as seen in Apple Mail, but it will now require the user to subclass CPTokenField, override layoutSubview and set the frame size to the size of the scroll view's document view.
2010-10-21 15:56:17 -03:00
Brian Donovan 7be6352531 Add format parameter index support to sprintf.
This is primarily useful in cases when the format string can vary, but the argument order will not, as is often the case with format strings in Localized.strings files.

From http://perldoc.perl.org/functions/sprintf.html:

An explicit format parameter index, such as 2$. By default sprintf will format the next unused argument in the list, but this allows you to take the arguments out of order.

See also this Cocoa example: http://stackoverflow.com/questions/1063843/is-there-a-way-to-specify-argument-position-index-in-nsstring-stringwithformat
2010-10-21 09:54:51 -07:00
Randall Luecke f2391cb150 Merge branch 'master' of git://github.com/280north/cappuccino 2010-10-21 12:02:06 -04:00
Randall Luecke 09c02c5884 Typeo in group items in outlineview. 2010-10-21 12:01:34 -04:00
Klaas Pieter Annema 71d02abc28 add global to disable string size caching 2010-10-21 17:36:09 +02:00
Alexander LjungbergandKlaas Pieter Annema 367efe590e Fixed with the new string size optimisation: the cache value was returned by reference and something in the CPButton path for image and text buttons changed it causing text to become misaligned. A defensive copy avoids this problem. 2010-10-21 17:36:09 +02:00
Klaas Pieter Annema afcce49455 improve CPString sizeOfString performance by caching the calculated result 2010-10-21 17:36:09 +02:00
Alexander Ljungberg d63e4f8021 Remove some placeholder comments for methods which now exist. 2010-10-21 00:47:58 -03:00
Blair DuncanandRoss Boucher c9a4821d15 Fix for issue 951 - CPResponder flagsChanged does not fire when the key is up 2010-10-20 18:54:50 -07:00
Blair DuncanandRoss Boucher 696990f035 Fix for previous fix and modified the test file. 2010-10-20 18:48:29 -07:00
Blair DuncanandRoss Boucher ad0867ba7d Fix for issue 948 Custom Cursors not working 2010-10-20 18:48:24 -07:00
Antoine Mercadal 48ebd2e954 add tests for CPTabView 2010-10-20 00:05:03 +02:00
Antoine Mercadal 3d82203893 remove 'drunk' code and simply use resizing masks 2010-10-19 22:53:52 +02:00
Klaas Pieter Annema a3766a0f96 whitespace cleanup in NSTextField and NSSearchField 2010-10-19 15:12:53 +02:00
Klaas Pieter Annema 2eb27a6492 Don't adjust the origin and size of a text field during nib2cib
This interferes with Aparajita's auto-sizing of controls in initWithCoder:. Also it's better to calculate the size in initWithCoder: because the theme information is available.
2010-10-19 15:07:01 +02:00
Klaas Pieter Annema 991e213d02 give CPSearchField it's own theme class
Before this change it was not possible to theme CPSearchField separately from a CPTextField. Aristo still just uses the rounded theme style.
2010-10-19 14:21:00 +02:00
Joachim GarthandRoss Boucher 834480ff68 Fixed a bug in reverseTransformValue: that caused transformedValue: to be called instead of reverseTransformedValue: 2010-10-18 10:46:13 -07:00
cacaodevandRoss Boucher 678563a970 Accidental globals in CPNotificationCenter and Runtime.js 2010-10-18 10:15:40 -07:00
Randall Luecke 00e638f406 initWithCoder on CPTextField should respect the larger height value if it's set. 2010-10-18 01:30:25 -04:00
Alexander Ljungberg 6b37bae2c2 Fixed: removed the previous CPTimer DOM check - it doesn't work in Foundation. 2010-10-15 16:03:00 -03:00
Alexander Ljungberg a3a4aed0d2 Merge branch 'master' of github.com:280north/cappuccino 2010-10-15 15:00:40 -03:00
Alexander Ljungberg 8ec78f20d1 Implement _minimumFrameSize for CPTokenField tokens. Also honor min-size width - not used by Aristo but potentially useful for custom themes. 2010-10-15 12:40:09 -03:00
Alexander Ljungberg a821614939 Clean up code. 2010-10-15 12:36:57 -03:00
Randall Luecke e13d771560 Performance related fixes for tableview drawing. 2010-10-15 11:09:26 -04:00
Randall Luecke 49a0a3d86e Fix for parameter type change from a find/replace. 2010-10-15 02:10:29 -04:00
Randall Luecke 56bc94f98c Merge branch 'tableview-grouprows' 2010-10-15 01:52:57 -04:00
Randall Luecke f0b527b680 Selection fixes for group rows in the tableview. 2010-10-15 01:52:22 -04:00
Tom Robinson 58494c5c2a Merge branch 'master' of github.com:280north/cappuccino into integration 2010-10-14 16:38:45 -07:00
Tom Robinson c72e136370 Require latest versions of all package to eliminate deprecation warnings. 2010-10-14 16:38:06 -07:00
Alexander Ljungberg b4c8da8f3d Fix CPTokenField imports. 2010-10-14 20:21:00 -03:00
Alexander Ljungberg 612e8c3f0b Add DOM checks to CPTimer's window.setTimeout bridge code. 2010-10-14 20:20:20 -03:00
Tom Robinson 9763cef196 Merge branch 'fix-deprecation-warnings' of http://github.com/paulbaumgart/cappuccino into paulbaumgart-fix-deprecation-warnings 2010-10-14 16:16:02 -07:00
Alexander Ljungberg ebd83b4941 Merge branch 'fix-cptokenfieldtoken-sizetofit' of http://github.com/primalmotion/cappuccino into primalmotion-fix-cptokenfieldtoken-sizetofit 2010-10-14 19:42:33 -03:00
Alexander Ljungberg 48d3ae61c5 Merge branch 'master' of github.com:280north/cappuccino 2010-10-14 19:38:11 -03:00
Alexander Ljungberg cfba019e3d CPCoding support for CPResponder menus. This allows context menus to be set for collection view items through the item prototype. 2010-10-14 19:36:48 -03:00
Brian DonovanandRoss Boucher 2037ab9a5e -[CPScrollView setContentView:] did not allow changing the content view. 2010-10-14 11:25:29 -07:00
Paul BaumgartandRoss Boucher 3287b02816 add script to automatically detect missing @imports and have it run from "jake test-only" 2010-10-13 18:48:46 -07:00
Paul BaumgartandRoss Boucher 12deb6859e Make CPCompatibility a little more CommonJS friendly. 2010-10-13 18:48:37 -07:00
Paul BaumgartandRoss Boucher 98393c66fc change a 'self' to a 'super' to fix infinite recursion 2010-10-13 18:41:59 -07:00
Ross Boucher 74bedf6dcd Add a missing import to the ArrayController test. 2010-10-13 18:39:46 -07:00
Brian DonovanandRoss Boucher b5d0054f94 -[CPIndexSet shiftIndexesStartingAtIndex:by:] did not properly adjust count.
When clipping a range (i.e. some or all of it went below the lower bound) as a result of
calling shiftIndexesStartingAtIndex:by: with a negative delta, the CPIndexSet did not adjust
the index count, which caused calls to -lastIndex to fail.

This caused -[CPArrayController removeObject:] to fail when the object removed was at index 0.
2010-10-13 18:20:20 -07:00
Antoine Mercadal 560c971aeb capp_lint 2010-10-13 13:41:35 +02:00
Antoine Mercadal 8fc465b63a fix: CPTabView not resizable
fix: delegate problem with uninitialized variable
2010-10-13 13:37:28 +02:00
Antoine Mercadal ca0c68c9bf fix: CPTokenFieldToken impacted by new CPTextField sizeToFit behaviour 2010-10-13 13:34:37 +02:00
Klaas Pieter Annema 6c663ddf32 nib2cib NSTableColumn dataCell's alignment property 2010-10-12 16:30:14 +02:00
Klaas Pieter Annema 7129094e26 always archive the table column it's dataView when it's set
Don't equality check so the data view is always re-archived when it's set. A dataView with a different font size should be re-archived, but will not be if we check for equality.
2010-10-12 13:47:15 +02:00
Klaas Pieter Annema 802d7d53b0 fix multiline bezeled textfields being sized when initialized from coder 2010-10-12 11:26:28 +02:00
Klaas Pieter Annema c4a074a92d Merge branch 'CPTextField-height-fix' of http://github.com/aparajita/cappuccino into aparajita-CPTextField-height-fix 2010-10-12 10:54:38 +02:00
Klaas Pieter Annema fe35823b46 implement NSFormatter nib2cib support 2010-10-11 12:35:45 +02:00
Alexander Ljungberg 8439dc1c0f CPKeyBinding description message. Decouple CPKeyBinding physical key string parsing from cache setup to make CPKeyBinding more reusable in user code. 2010-10-10 01:35:30 -03:00
Alexander Ljungberg db8e132ef2 Whitespace and style fixes. 2010-10-09 22:07:57 -04:00
Alexander Ljungberg 7e0c61bef0 Replace a non ASCII character. 2010-10-09 22:02:34 -04:00
Alexander Ljungberg 2c4bb019ba Add license and creator to _CPCornerView.j. 2010-10-09 22:01:21 -04:00
Alexander Ljungberg 0bd03b8d58 Closes #926. Don't display a menu when a CPPopUpButton is right clicked, especially not a broken one. 2010-10-09 21:54:19 -04:00
Alexander Ljungberg e62af384ea Merge branch 'fix-imports' of http://github.com/paulbaumgart/cappuccino into paulbaumgart-fix-imports 2010-10-09 21:32:58 -04:00
Klaas Pieter Annema e23c70b5c4 Merge remote branch 'aparajita/NSCell-layout' 2010-10-09 16:25:48 +02:00
Aparajita Fishman c8639cc8cd Fixed the attribution 2010-10-08 23:18:48 -04:00
Aparajita Fishman 87c9f9ef03 Added bezeled multi-line field with wrapping 2010-10-08 17:52:47 -04:00
Aparajita Fishman ab430b3574 Forgot to update sizeToFit documentation. 2010-10-08 10:18:38 -04:00
Aparajita Fishman b8ae14d3a8 Fixes and more tests:
- Fixed _minimumFrameSize to take into account bezel and line break mode.

- Added test to show how sizeToFit was broken for multi-line labels in the old code.

- Added test to verify that behavior is correct for single-line labels.
2010-10-08 10:17:12 -04:00
Randall Luecke ca0ed0ccb9 Merge branch 'master' of git://github.com/280north/cappuccino 2010-10-08 00:48:40 -04:00
Randall Luecke 99201dc3db Initial commit for group rows in the TableView. Drawing code still needs to be cleaned up a LOT... still buggy. i.e. after you select a group row, any rows after that which are selected then get selected with a gray highlight color. 2010-10-08 00:44:17 -04:00
Klaas Pieter Annema 5074938437 implement KVO dependent key path support 2010-10-07 21:17:28 +02:00
Aparajita Fishman 637b8bed33 wraps flag was not being calculated correctly, added flags for other layout modes 2010-10-07 10:27:05 -04:00
Klaas Pieter Annema fcd75d72e0 remove cancel: action from CPResponder 2010-10-07 12:10:42 +02:00
Klaas Pieter Annema 5b82417698 Merge branch 'CPKeyValueObservingOptionInitial-fix' of http://github.com/eventualbuddha/cappuccino into eventualbuddha-CPKeyValueObservingOptionInitial-fix 2010-10-07 10:37:50 +02:00
Paul Baumgart 45ebe2c905 Fix deprecation warnings 2010-10-06 23:04:46 -07:00
Ross Boucher ff2aa51a68 Fix accidental global in CPObject. 2010-10-06 19:41:45 -07:00
Aparajita Fishman b6491f7bb8 CPTextField -initWithCoder was not ensuring the frame size was high enough. The default label height in IB is 17px, which unmodified was cutting off the bottom pixel of labels in Cappuccino. 2010-10-06 08:43:21 -04:00
Klaas Pieter Annema e78200838f don't make a modally run window the main window 2010-10-06 09:04:54 +02:00
Paul Baumgart 01852d8075 Fix a bunch of missing @imports.
All classes (excluding the ones prefixed with underscores) in Foundation
and AppKit can now be loaded individually except CPOpenPanel and
CPSavePanel. These two classes have some sort of dependency cycle
that seems impossible to resolve without forward declarations (which
we don't have).
2010-10-05 15:54:25 -07:00
Brian Donovan 0ce115bc9c Ensure observeValueForKeyPath:ofObject:change:context is called consistently.
During the "normal" callback for new and old values, the ofObject:
parameter passed to the observer is the original receiver of the
addObserver:forKeyPath:options:context: call, but that isn't the case
with the call caused by the CPKeyValueObservingOptionInitial option.
This commit uses _targetObject, the receiver of the addObserver:...
call, rather than self, the _CPKVOProxy.
2010-10-05 07:45:43 -07:00
Brian Donovan b430e2ef65 Fix "differ" that was supposed to be "defer". 2010-10-04 15:02:41 -07:00
Klaas Pieter Annema a99e976610 Merge branch 'CPControl-bridge' of http://github.com/aparajita/cappuccino into aparajita-CPControl-bridge 2010-10-04 10:44:03 +02:00
Klaas Pieter Annema 9b4807de26 Merge branch 'CPButton-copy-bounds' of http://github.com/aparajita/cappuccino into aparajita-CPButton-copy-bounds 2010-10-04 10:39:32 +02:00
Alexander Ljungberg 56a0184258 Fixed a missing comma in the token field theme descriptor. 2010-10-03 15:39:17 -04:00
Alexander Ljungberg b64390077a Remove margin from token fields without bezel so that the tokens line up with text labels at the same X coordinate. 2010-10-03 15:31:48 -04:00
Alexander Ljungberg e7e9c24aaa Fix accidental globals in CPTokenField, convert tabs to spaces. 2010-10-03 00:35:57 -04:00
Alexander Ljungberg 9eba3c0cec Make theme work for token fields without bezeled:NO. Demo of auto suggest in test app. 2010-10-03 00:29:29 -04:00
Alexander Ljungberg 69b30df8e6 Fixed: with more than one token field, the separator character for all fields would be bound to that of the first field. 2010-10-03 00:23:05 -04:00
Alexander Ljungberg ca2aab1198 Visual CPTokenField test application. 2010-10-02 22:45:05 -04:00
Alexander Ljungberg 1b45f621a7 Created and implemented a first draft Aristo theme for CPTokenField. 2010-10-02 22:41:38 -04:00
Alexander Ljungberg 421a51f008 Made CPTokenField themeable separately from CPTextField since the placeholder insets must be handled differently. 2010-10-02 19:38:12 -04:00
Alexander Ljungberg cce21e7e87 Fixed: forgot to define a theme name for the CPTokenField close button. 2010-10-02 19:38:01 -04:00
Alexander Ljungberg f6236ca317 Fixed: CPTokenField setObjectValue:nil did not clear the token field. 2010-10-02 19:37:48 -04:00
Alexander Ljungberg 77e10c94e9 Fixed: if setValue was called to clear a token field, the placeholder message would not appear. 2010-10-02 19:37:37 -04:00
Alexander Ljungberg 38cc1943ee Reverse binding support for deleting tokens using the delete button. Fixed: if the last token was deleted using the close button without the token field being the first responder, the placeholder message would not appear. 2010-10-02 19:37:31 -04:00
Alexander Ljungberg 3b1047e97d Implemented tokenizingCharacterSet property for CPTokenField. This changes the default tag separator to "," and allows tags with spaces. The previous behaviour can be restored using [field setTokenizingCharacterSet:[CPCharacterSet characterSetWithCharactersInString:@" "]]. 2010-10-02 19:37:17 -04:00
Alexander Ljungberg 34c1a1ce10 Fixed: if a CPTokenField was a subview of a container not at the top at the window, such as is often the case with a toolbar, the autocomplete view of CPTokenField would appear offset downwards.
Also switched the background of the autocomplete view to a simple menu style for now since the other graphics were not available.
2010-10-02 19:37:08 -04:00
Alexander Ljungberg b0e3e38791 Reverse bindings support for when tokens are deleted through the close button. 2010-10-02 19:36:55 -04:00
Alexander Ljungberg 124a63736f Made CPTokenField themeable. Todo: the autocomplete drop-down is still hardcoded and Aristo style images are needed. 2010-10-02 19:36:24 -04:00
Alexander Ljungberg 656e0eb28e Whitespace cleanup in preparation for the next merge. 2010-10-02 19:19:51 -04:00
Alexander Ljungberg 688c46c793 Fixed some typos in the previous CPTokenField commit. 2010-10-02 15:36:35 -04:00
Alexander Ljungberg ee2228a83c Fixed: if [CPTokenField setObjectValue:X] was called while the token field was the first responder, the input value would be set to a string version of the object value due to CPTextField's setObjectValue method. 2010-10-02 15:36:29 -04:00
Klaas Pieter AnnemaandAlexander Ljungberg 9f4dd3c2b8 added various hacks to make the cptokenfield work with the new enstore admin 2010-10-02 15:36:24 -04:00
Klaas Pieter AnnemaandAlexander Ljungberg c80a28077a fixed some tokenfield issues 2010-10-02 15:36:19 -04:00
Klaas Pieter AnnemaandAlexander Ljungberg 47c631c58e added CPTokenField 2010-10-02 15:36:11 -04:00
Alexander Ljungberg ed4235d2f9 Fixed: setting any binding on a text field - even on an attribute like 'hidden' - would clear its placeholder string. 2010-10-02 14:42:06 -04:00
Alexander Ljungberg 16e9fce5b5 Unit test exposing a new bug: setting a binding on a text field causes it to lose its placeholder string. 2010-10-02 14:38:34 -04:00
Alexander Ljungberg 2e22a0d5e8 Merge branch 'master' of github.com:280north/cappuccino 2010-10-01 17:30:17 -04:00
Alexander Ljungberg 1ae31c9374 Style fixes. 2010-10-01 17:28:55 -04:00
Klaas Pieter Annema 973c43843d improve multiple selection login in CPCollectionView 2010-10-01 11:31:59 +02:00
Alexander Ljungberg 90709156c6 Merge branch '_CPImageAndTextView-tweaks' of http://github.com/aparajita/cappuccino 2010-09-30 23:52:27 -04:00
Alexander Ljungberg 0d15e59d0a CPSlider code cleanup. 2010-09-30 23:51:12 -04:00
Aparajita Fishman 60fcb24159 De-lint, whitespace cleanup, typos 2010-09-30 21:14:47 -04:00
Aparajita Fishman a175e71906 - Fixed type of _textSize.
- Changed NULL to nil.
2010-09-30 17:30:58 -04:00
Aparajita Fishman c3b5dc747a CPButton bezelRectForBounds and contentRectForBounds were modifying the bounds parameter in place without copying it. 2010-09-30 17:27:06 -04:00
Klaas Pieter Annema e527c7e19f fix another bug introduced in my last commit 2010-09-30 18:58:40 +02:00
Klaas Pieter Annema 790327fbe8 revert d18bba6b03, it had unexpected side effect 2010-09-30 18:44:00 +02:00
Klaas Pieter Annema d18bba6b03 make sure CPScrollView always sets up it's corner and header view when initializing from coder 2010-09-30 18:40:45 +02:00
Aparajita Fishman 0a752be53c Moved methods defined by BRIDGE into real method declarations so they will be included in doxygen docs, lint cleanup. 2010-09-30 08:37:36 -04:00
Klaas Pieter Annema b221cc1853 properly decode allows multiple selection in CPCollectionView 2010-09-30 13:54:34 +02:00
Klaas Pieter Annema 2935651578 only nib2cib bundle if bundle path is set in nib 2010-09-30 13:13:18 +02:00
Paul Baumgart ca2ae22f15 Fix non-ASCII characters in CPDictionary.j and CPFormatter.j 2010-09-29 18:21:10 -07:00
Mike Fellows 1c597eb0df Fix regression in CPBox's setBorder 2010-09-29 00:05:15 -07:00
Alexander Ljungberg 28dd74444f Fixed a string of accidental globals in CPScroller. 2010-09-28 19:50:20 -04:00
Alexander Ljungberg 28cf834e0b Merge branch 'CGGradientCreateWithColorComponents-location-fix' of http://github.com/eventualbuddha/cappuccino 2010-09-28 19:29:46 -04:00
Alexander Ljungberg 4dc102a3cf Applied coding standards. 2010-09-28 19:00:59 -04:00
Brian Donovan 23a654d57a Allow null locations per Quartz 2D documentation.
See http://developer.apple.com/library/ios/#DOCUMENTATION/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_shadings/dq_shadings.html%23//apple_ref/doc/uid/TP30001066-CH207-TPXREF101
2010-09-28 08:22:09 -07:00
Klaas Pieter Annema ffcbf87858 add basic support for drawing separators to CPBox 2010-09-28 14:50:20 +02:00
Ross Boucher 32a0e950fe Allow comparators to return any value > 1 to indicate CPOrderedDescending. 2010-09-28 16:46:39 +05:30
Randall Luecke f21ec37531 Fix for NativeHost windows becoming inactive when then go to the background. 2010-09-28 00:18:02 -04:00
Paul BaumgartandRandall Luecke a8d02f43e2 minor CPTableView clean-ups-- fix missing semi-colon, missing parameter type, and missing space 2010-09-27 22:43:58 -04:00
Paul BaumgartandRandall Luecke 7e863e7e96 selectTabViewItemAtIndex does not look up the TabViewItem to send to the delegate, which causes a JS ReferenceError; this commit fixes that 2010-09-27 22:42:55 -04:00
Randall Luecke 588577bd96 try to use setLocalStorageDatabasePath or use _setLocalStorageDatabasePath if not
Conflicts:

	Tools/NativeHost/AppController.m
2010-09-27 22:38:32 -04:00
Randall Luecke ee64c5d832 Proper decoding of delegate and datasource for the tableview. 2010-09-27 17:56:48 -04:00
Antoine MercadalandRandall Luecke e55cbbdc0e Support for localstorage in NativeHost 2010-09-27 16:27:04 -04:00
Klaas Pieter Annema 65c48004ba properly handle key events manually in the tableview
Commit cf6dc3fa5e was wrong. This commit should fix that.
2010-09-27 15:56:00 +02:00
Klaas Pieter Annema 4211abd0b0 handle tab key as early as possible in CPWindow sendEvent: 2010-09-27 11:53:07 +02:00
Klaas Pieter Annema cf6dc3fa5e Manually handle key events in CPTableView 2010-09-27 11:50:23 +02:00
Klaas Pieter Annema fb3da5c5bd don't handle key events directly in CPScrollView
In stead CPScrollView will just pass the keyDown: event up the responder chain. If the event reaches the window, the window will send the correct action back to the first responder, if no responder before CPScrollView in the chain handles the event, CPScrollView will.
2010-09-27 11:50:23 +02:00
Klaas Pieter Annema e6bd921746 fix CPWindow to only sent certain not handled keys as actions
In Cocoa CPWindow will only send moveDown: (down arrow), moveUp: (up arrow), moveLeft: (left arrow), moveRight: (right arrow), pageUp: (page up), pageDown: (page down) and complete: (escape) down the responder chain. This commits makes us fully compatible with Cocoa except that we send scrollPageDown: and scrollPageUp: in stead of pageUp: and pageDown:.
2010-09-27 11:50:23 +02:00
Francisco Ryan Tolmasky I 40dcfbd72c Merge branch 'master' of github.com:280north/cappuccino 2010-09-27 06:49:18 +05:30
Francisco Ryan Tolmasky I 48d14840ee Fix file encoding for CPTableView.j.
Reviewed by me.
2010-09-26 15:40:36 +05:30
Klaas Pieter Annema c9e0ab654f test observations during setSelectionIndexes 2010-09-23 10:59:00 +02:00
Klaas Pieter Annema d8c0d2da8e don't reverse set binding if textfield is showing a bindings placeholder 2010-09-23 10:35:42 +02:00
Klaas Pieter Annema e59f20668b don't set objectValue in resignFirstResponder if it didn't change
This change makes sure that the textfield doesn't sent change notifications if the value didn't actually changed when resigning first responder.
2010-09-23 10:35:41 +02:00
Klaas Pieter Annema 8fe67b73da implement _setCurrentValueIsPlaceholder in CPTextField
CPKeyValueBinding will sent _setCurrentValueIsPlaceholder: to indicate to an object that current value is a placeholder and should be displayed as such. This commit implements the method for CPTextField and adds a unit test to test the behavior.
2010-09-23 10:35:41 +02:00
Klaas Pieter Annema 2fba03dc75 fix style issues in CPTextField and CPKeyValueBindingTest 2010-09-23 10:35:41 +02:00
Klaas Pieter Annema 71f8d1db74 call selectionWill and didChange when setting selection indexes 2010-09-23 10:35:41 +02:00
Klaas Pieter Annema 098131e252 coding guideline improvements for CPArrayController 2010-09-23 10:35:41 +02:00
Klaas Pieter Annema afc5b72092 made setting binding placeholder values slightly less hacky 2010-09-23 10:35:41 +02:00
Klaas Pieter Annema 14f494a25d Properly set multiple value placeholders on textfields.
Previously CPKeyValueBinding would just set the binding marker placeholder values as the stringValue of the textfield. This commit fixes that and properly sets those values as the placeholder value.
2010-09-23 10:35:41 +02:00
Francisco Ryan Tolmasky I 8bc665f355 Merge branch 'master' of github.com:280north/cappuccino 2010-09-23 10:43:08 +05:30
Brian DonovanandRoss Boucher 6dd872f2d2 Fix CPScrollView -contentSize return type. 2010-09-21 21:43:28 +05:30
Mike FellowsandRandall Luecke 461bb65263 Set vertical slider disabled track-color to the proper background images, stop overwriting the horizontal slider disabled track-color background images with those meant for the vertical slider - fixes issue #737 2010-09-20 01:37:03 -04:00
Derek HammerandRandall Luecke 266bed7dc9 Use include instead of push to increase performance of jake. 2010-09-20 01:33:36 -04:00
Randall Luecke 9777e4c52f Added a missing import to the new CPTabView, and fixed the import for the test. 2010-09-20 01:28:57 -04:00
Derek HammerandRandall Luecke dd89a98242 Renaming class to CPTabView from CPTabView2. Also doing a little clean up for style. 2010-09-20 01:21:45 -04:00
Derek HammerandRandall Luecke 9b57d04181 Tabs to spaces 2010-09-20 01:20:58 -04:00
Derek HammerandRandall Luecke 8e74418a5c Replacing CPTabView with new one 2010-09-20 01:20:48 -04:00
Derek HammerandRandall Luecke 3350579675 Patch to fix error. :( 2010-09-20 01:20:40 -04:00
Derek HammerandRandall Luecke 46c14f3766 Adding the real skeleton
Copying previous constants

Removing unnecessary constants

Borrowing initialization from my old implementation.

Refactoring the initialization method and adding setBackgroundColor: override.

Removing +initialize (no theming support yet) and -viewDidMoveToWindow (not sure why this was there?)

Implement the bulk of the new CPTabView

Adding delegate selectors. Don't think this is complete, though. What about when a user clicks on a segmented tab control?!

Adding delegate

Think I may have fixed the delegate blocking for selected segment control items

Adding tests. Fixing a bug by reverting to old way. Delegates still broken.

Cleaning up the test.

Resolving delegate issues (thanks Saikat!).

Switching tab appearance based on type enum. Updating tests to slightly test this.

Conflicts:

	AppKit/CPTabView2.j
2010-09-20 01:20:31 -04:00
Randall Luecke 0aa65de6df Fix for CPCookie not working after DOM checks. 2010-09-19 23:26:52 -04:00
Francisco Ryan Tolmasky I ea7257c00d Merge branch 'master' into @each 2010-09-19 15:21:48 -07:00
Francisco Ryan Tolmasky I 06bb1a96f3 Fix for objjc not compiling.
Reviewed by me.
2010-09-19 15:21:01 -07:00
Francisco Ryan Tolmasky I 2f0de57c92 Merge branch 'master' into @each
Conflicts:
	Foundation/CPArray.j
2010-09-19 15:06:16 -07:00
Francisco Ryan Tolmasky I 70e4dd16df A few more parser tests and reorg of tests.
Reviewed by me.
2010-09-19 08:18:54 -07:00
Francisco Ryan Tolmasky I b66034ef38 First couple of Objective-J language spec tests.
Reviewed by me.
2010-09-18 23:50:06 -07:00
Francisco Ryan Tolmasky I d3c86aeefd Cleanup for previous undo patch and added a few test cases.
Reviewed by me.
2010-09-18 21:47:43 -07:00
Blair DuncanandFrancisco Ryan Tolmasky I 212feff636 CPUndoManager -added support for setActionName to enable the undo/redo menu to automatically update with the value passed as the action name. Test file included. 2010-09-18 20:30:43 -07:00
Alexander Ljungberg b1b0cea27e Merge remote branch 'hammerdr/clean_fix' 2010-09-17 21:25:05 -04:00
Alexander Ljungberg 5742608595 Recreated Aparajita Fishman's documentation related Jakefile change from 345343ef52. 2010-09-17 21:21:40 -04:00
Aparajita FishmanandAlexander Ljungberg f46f97f8b6 Implemented doxygen parsing of @accessors synthesized methods, moved @accessors declarations in .h files to a comment to prevent improper parsing. 2010-09-17 21:19:02 -04:00
Alexander Ljungberg 7692f80f64 Additional fixes of inadvertent globals. 2010-09-17 16:48:00 -04:00
Alexander Ljungberg bb811238f3 Fixed a number of inadvertent globals and improved code style. 2010-09-17 16:46:55 -04:00
Derek Hammer 68c657eb66 Adding the $CAPP_BUILD directory to the "jake clean" and "jake clobber" commands so that they act as expected. 2010-09-17 13:03:50 -05:00
Nicholas Small b5bae40a0c Fix the short circuit in CPCollectionView -setSelectionIndexes: 2010-09-17 12:23:36 -04:00
Michael VillarandNicholas Small f7c68736f0 Ctrl+click only sends right click on Mac. 2010-09-17 12:21:57 -04:00
Mike FellowsandKlaas Pieter Annema 7d855a9c09 Fix minor typos, some accidental globals, missing coma and missing semicolon 2010-09-17 11:03:32 +02:00
Nicholas Small d59d141302 Fix a bool that's supposed to be an int in CPUndoManager -groupingLevel. 2010-09-16 13:26:17 -04:00
Aparajita FishmanandKlaas Pieter Annema 0c4ce1e756 Additions to the theme API to open it up to developers and provide access to theme attributes defined in ThemeDescriptors.j:
- Current theme blend is available via CPApplication -themeBlend.

- List of themes is available via CPApplication -themes.

- CPThemeBlend adds the following methods:

themes
themeNames

- CPTheme adds a number of methods to access theme attributes:

classNames
attributesForClass:
attributeNamesForClass:
attributeWithName:forClass:  (was _attributeWithName:forClass:)
valueForAttributeWithName:forClass
valueForAttributeWithName:inState:forClass:

- _CPThemeAttribute -values was added to access the dictionary of attribute values.

- Theme browser application that demonstrates the API.

- In the course of making the test app, added the function CGInsetEqualToInset().
2010-09-16 10:28:06 +02:00
Alexander Ljungberg 9b8cadb91c Fixed some additional accidental globals. Very addictive this. 2010-09-15 17:41:58 -04:00
Alexander Ljungberg 9c9d6a7fdc Merge branch 'master' of github.com:280north/cappuccino 2010-09-15 17:25:54 -04:00
Alexander Ljungberg fb31267cc1 Fixed two accidental globals found while testing Aparajita Fishman's capp_check utility. 2010-09-15 17:23:48 -04:00
Alexander Ljungberg b194d407d3 Whitespace cleanup. 2010-09-15 17:19:45 -04:00
Klaas Pieter Annema 57813ea3fb change CPButton imageOffset theme property to image-offset 2010-09-15 12:34:16 +02:00
Alexander Ljungberg bce89ca75b Merge branch 'master' of github.com:280north/cappuccino 2010-09-14 15:39:23 -04:00
Alexander Ljungberg 7204e73c22 Minor code cleanup. 2010-09-14 15:38:45 -04:00
Alexander Ljungberg 541f5b8948 Test editable text field text selection in a modal window. 2010-09-14 15:38:45 -04:00
Alexander Ljungberg c5d471b31b Fixed: if a text field in a modal window was clicked, it would become deselected. This prevented text selection by dragging or by double click. The problem was that the DOM event guard was always enabled when a modal window was on screen and this prevented the normal mouse event pass through to the text field input element. 2010-09-14 15:38:45 -04:00
Klaas Pieter Annema ac26827f32 make CPTableHeaderView divider color theme-able 2010-09-14 14:47:10 +02:00
Klaas Pieter Annema 677cb4638f fix bug where CPViewController viewDidLoad is called to early
The bug was caused by connections (outlets) being defined in undefined order. Sometimes the view connection was decoded and connected before other connections, because setView: would automatically call viewDidLoad the first time a view was set viewDidLoad was called before the entire view was actually loaded.

ViewDidLoad is now only called from setView: if the _view === nil and no view is currently being loaded.
2010-09-14 12:58:47 +02:00
Klaas Pieter Annema 32348148b8 fixed typos in CPViewController documentation 2010-09-14 12:12:50 +02:00
Klaas Pieter Annema f79edc7bfb fix scroller being offset 1 pixel when headerview had the same height as corner view 2010-09-14 12:05:39 +02:00
Klaas Pieter Annema f7c7ee447d set proper autoresizing for ScrollviewTheming test color well 2010-09-14 12:05:39 +02:00
Tom Robinson 1220555936 Fix for CPProxy not returning the return value 2010-09-13 16:44:45 -07:00
Sami SamhuriandKlaas Pieter Annema 032639234e Use CPTextFields for RGB, HSB, and hex inputs in CPSliderColorPicker
The old DOM based fields only accepted a few characters. Backspace and
other expected functionality was broken. Switching to CPTextFields
makes them behave as expected.
2010-09-13 15:20:26 +02:00
Saikat ChakrabartiandRandall Luecke cdf9a8c2a7 Adding a DOM check for CPCookie 2010-09-13 01:30:46 -04:00
Aparajita FishmanandAlexander Ljungberg 6fbdf7b400 Support for NSBox in nib2cib and some fixes to CPDrawTiledRects/CPDrawColorTiledRects.
- The default box background color is now clear, that is what Cocoa does.

- Bezel drawing uses CPDrawTiledRects, obeys border width.

- CPDrawTiledRects/CPDrawColorTiledRects explicitly sets the line width and saves/restores the graphics state.

- Whitespace cleanup in CPBox.
2010-09-10 20:35:38 -04:00
Alexander Ljungberg 4983e97884 Use CPNotFound instead of -1 in CPTableView editedRow and editedColumn for clarity. 2010-09-10 20:27:22 -04:00
Alexander Ljungberg cc7d50f505 Fixed: CPTableView editedRow returned the edited column, not the edited row. 2010-09-10 20:26:01 -04:00
Alexander Ljungberg f2f737fcd3 Merge remote branch 'hammerdr/subclassable' 2010-09-10 20:18:30 -04:00
cacaodevandAlexander Ljungberg c47e6af6e4 nib2cib: Fix a bug where a view's tag of 0 in Interface Builder was decoded as -1 in capp. This is the default when instancing in code, not when unarchiving a Nib. Testing: in Tests/Manual/NibApp, just logging a textfield's tag 2010-09-10 20:03:28 -04:00
Alexander Ljungberg 5e6485b622 Merge remote branch 'samsonjs/rightclick' 2010-09-10 19:26:12 -04:00
Alexander Ljungberg bb2ec9098b Merge remote branch 'aparajita/CPLog-formatter' 2010-09-10 19:15:21 -04:00
Alexander Ljungberg 4e4cc65645 Style and whitespace cleanup. 2010-09-10 19:07:48 -04:00
Arkadiusz MłynarczykandAlexander Ljungberg ddfac8d717 - moved componentsSeparatedByCharactersInSet: into CPCharacterSetAdditions CPString category
- added tests for componentsSeparatedByCharactersInSet:
- ensured Cocoa compatibility of componentsSeparatedByCharactersInSet:
- added new test for CPString boolValue
- fixed CPString boolValue (" ++01" should return NO as in Cocoa, previously it returned YES)
2010-09-10 18:58:18 -04:00
Arkadiusz MłynarczykandAlexander Ljungberg 009683ddd4 - Exception raising in componentsSeparatedByCharactersInSet: when separator parameter is nil
- Added support for edge cases (string is empty or string doesn't contain characters from separator set).
2010-09-10 18:58:10 -04:00
Arkadiusz MłynarczykandAlexander Ljungberg 8eefb90944 - implemented componentsSeparatedByCharactersInSet: 2010-09-10 18:58:02 -04:00
Klaas Pieter Annema 6bc8a53618 Merge branch 'scrollview-theming' 2010-09-10 14:37:51 +02:00
Klaas Pieter Annema de73c05316 add colorwell to change bordercolor to Scrollview theming test 2010-09-10 14:28:09 +02:00
Klaas Pieter Annema fba8b85c90 theming changes to CPScrollView
- Add bottom corner view and make it's background color a theme property
- Make the border color themeable
2010-09-10 14:20:19 +02:00
Klaas Pieter Annema 20557190d9 make the scroller width themeable 2010-09-10 14:20:18 +02:00
Klaas Pieter Annema 4e4e7ae015 properly position the vertical scrollbar
The vertical scrollbar would be one pixel of if there was:

- no headerview (overlapping the border)
- a headerview, but no cornerview
2010-09-10 14:20:18 +02:00
Klaas Pieter Annema 36c3c94d3b add the ability to turn header view on and off in ScrollviewTheming test 2010-09-10 14:20:18 +02:00
Klaas Pieter Annema 64b733b1ea remove bottom corner view drawing in CPScrollView 2010-09-10 14:20:18 +02:00
Klaas Pieter Annema 67a023a992 set proper autoresizing mask for theming controls in ScrollviewTheming test app 2010-09-10 14:20:18 +02:00
Klaas Pieter Annema b6e7d4149d add scrollview theming test application 2010-09-10 14:20:18 +02:00
Klaas Pieter Annema bcacee2147 draw the bottom corner in CPScrollView 2010-09-10 14:20:17 +02:00
Klaas Pieter Annema b75dcd7ac4 made the scrollview line border color themeable 2010-09-10 14:20:17 +02:00
Klaas Pieter Annema e77d28f761 properly decode CPColorWell color as an object in stead of bool 2010-09-10 14:17:39 +02:00
Sami SamhuriandKlaas Pieter Annema bc9645aa4f Added a test for hex conversions in CPColor 2010-09-10 10:02:21 +02:00
Sami SamhuriandKlaas Pieter Annema d52cbb7077 Don't set placeholder text on hex text field 2010-09-10 10:02:14 +02:00
Sami SamhuriandKlaas Pieter Annema ba9df402b0 Use a CPTextField for hex input in CPSliderColorPicker
The old DOM based field only accepted a few characters, and not even hex
chars. Backspace and other expected functionality was broken. Switching
to a CPTextField makes it behave as expected.
2010-09-10 10:02:04 +02:00
Sami SamhuriandKlaas Pieter Annema c78b5e580a Reliably convert colors to hex strings
Converting a hex string to CPColor and back to a hex string now returns
the same initial hex string. (Fixed an off-by-one error)
2010-09-10 10:01:57 +02:00
Aparajita FishmanandKlaas Pieter Annema ce2c662872 Fixes to previous CPButton image positioning commit.
- Checkbox and radio selected states would not show in the images. It turns out that the image and alternate image cannot be encoded->decoded->set without messing up the theme, and unfortunately the theme blending task (during a jake build) would do so. So for now this means that we cannot encode non-theme images with a button class, which is unlikely to happen.

- Since we cannot access themes in the NS classes, I went ahead and started to make some constants in a few control classes so that the values can be changed in one place and affect the theme and nib2cib.
2010-09-10 09:56:26 +02:00
Klaas Pieter Annema 04b331ad55 decode CPTableColumn resizing mask as integer 2010-09-09 16:36:32 +02:00
Klaas Pieter Annema 35c026f92c Merge branch 'master' of github.com:280north/cappuccino 2010-09-08 22:14:34 +02:00
Aparajita FishmanandKlaas Pieter Annema 6680a1f2a7 Overhaul of CPButton and supporting classes to support image positioning the way Cocoa does 2010-09-08 22:13:39 +02:00
Klaas Pieter Annema 1ffbf7857f Overhaul of CPButton and supporting classes to support image positioning the way Cocoa does. 2010-09-08 22:10:20 +02:00
Klaas Pieter Annema e2741ba604 made press work with custom themes 2010-09-08 16:13:45 +02:00
Koen BokandKlaas Pieter Annema 5b7497093c Made flatten work with custom themes. 2010-09-08 16:12:22 +02:00
Klaas Pieter Annema b092ed8c2c only load Aristo from AppKit/Resources
Other themes are loaded from the main bundle's resource directory
2010-09-08 16:12:21 +02:00
Klaas Pieter Annema 2dd1a1b54d always return a boolean from CPKeyedUnarchiver decodeBoolForKey: 2010-09-08 13:28:40 +02:00
Klaas Pieter Annema 1952bc2b76 unhide the cornerview when a tableview is unarchived 2010-09-08 13:28:18 +02:00
Klaas Pieter Annema b6da0fdf06 start of CPSplitView theming 2010-09-07 10:23:21 +02:00
Derek Hammer 7f7571a2d1 Adding tests to verify the behavior of CPDictionary when subclassed. 2010-09-06 11:44:27 -05:00
Alexander Ljungberg e704d42adb Fixed: if CPArrayController setPreserveSelection was off and a selected item disappeared, an invalid selection state could occur. The error was caused by a slightly overeager early-out optimisation in __setSelectionIndexes. 2010-09-04 22:12:08 -04:00
Sami Samhuri 5ff9683cd7 Send the correct event when right-clicking in a focused text field 2010-09-03 10:18:26 -07:00
Aparajita Fishman 7d36daa5b7 Added documentation for CPLogColorize 2010-09-03 11:45:06 -04:00
Aparajita Fishman 46956dbe9e Added a README 2010-09-03 11:36:11 -04:00
Aparajita Fishman 586e18f1a7 Custom formatter support (and fixes) for CPLog.
- A formatter function can be passed to the CPLogRegister functions. If the given level already has a provider for the given level, the formatter will be replaced with the one passed to the register function.

- Added CPLogColorize function to make it easy for users to colorize messages.

- CPLogRegisterRange now checks for min <= max, and  now correctly starts iterating from min.

- Moved colorization of log level to _CPFormatLogMessage.

- Whitespace cleanup.
2010-09-03 11:20:28 -04:00
luddepandRandall Luecke c489909542 Added manual test for cpscrollview behavior 2010-09-03 11:09:08 -04:00
Randall Luecke ad679e7c34 Merge remote branch 'luddep/native-scrolling-2' 2010-09-02 23:29:44 -04:00
luddep 75f6db436b fix for clearing the hiding of the scroll element timeout not working. This improved performance. Also make the actual dom element smaller and the inner one bigger, since sometimes deltas need to be larger than 150px. 2010-09-02 22:25:09 +02:00
Alexander Ljungberg bdcef193b7 Minor CPArrayTest cleanup. 2010-08-31 23:45:35 -04:00
Derek HammerandAlexander Ljungberg d377790e9d Adding some tests to verify behavior. 2010-08-31 23:41:51 -04:00
Alexander Ljungberg 9a31297249 Put the logging setup into the natural code path. 2010-08-31 22:33:11 -04:00
Aparajita FishmanandAlexander Ljungberg b4f7df4786 Graphics primitives
- Implemented CGRectDivide/CPDivideRect.
- Implemented CPDrawTiledRects/CPDrawColorTiledRects.
- Removed CPDrawGrayBezel and CPDrawGroove, they were not being done in a Cocoa-compliant way, and the Cocoa way is not really useful right now.
- Moved border drawing code back to CPScrollView since CPDrawGrayBezel/CPDrawGroove are gone.
- Test app to do simple demo of the new functions.
- Removed trailing whitespace.
2010-08-31 22:26:54 -04:00
Alexander Ljungberg 18d7dcc226 Closes #849. Test application to verify the graphical rendering of menus. 2010-08-31 22:18:26 -04:00
Sami SamhuriandAlexander Ljungberg f7ef182d33 Add 3px padding to the right of menu bar icons 2010-08-31 22:15:46 -04:00
Aparajita FishmanandAlexander Ljungberg be36e17bd8 Make the names in +themeShowcaseExcludes case-insensitive 2010-08-31 22:09:29 -04:00
Aparajita FishmanandAlexander Ljungberg 6b940116be Added ability to set sample text 2010-08-31 22:02:50 -04:00
luddep da8ea72593 fix for scrolling not working in windows other than the default bridge one. 2010-08-31 14:22:46 +02:00
luddep 5effa853a3 use visibility instead of display to hide the scroll dom element. Using display made the div reset its scroll offset. 2010-08-31 14:09:49 +02:00
luddep 0780a68fba fix for not being able to interact with DOM elements in views such as CPTextField 2010-08-31 09:36:54 +02:00
luddep b61192a050 Initial lower level native scrolling attempt. Fixes scroll deltas globally, rather than in just CPScrollView. 2010-08-30 12:27:28 +02:00
Alexander Ljungberg 9bc9a49b8f Merge branch 'master' of github.com:280north/cappuccino 2010-08-29 17:46:47 -04:00
Alexander Ljungberg 547f1fb786 While not used anywhere, the preprocessor 'peak' method was most likely meant to be called 'peek'. Renamed it. Also some minor code styling and whitespace fixes. 2010-08-29 17:42:22 -04:00
Blair DuncanandRandall Luecke b27560c51e Fix for issue 841 where the edit cursor would not always flash 2010-08-27 19:46:55 -04:00
Aparajita FishmanandAlexander Ljungberg 8dd1d20a2d Made sure to remove the .doc directories first, fixed exec 2010-08-27 19:29:11 -04:00
Aparajita FishmanandAlexander Ljungberg ad5badb0d7 Remove @import statements from source files, doxygen doesn't parse them correctly. 2010-08-27 19:28:23 -04:00
Aparajita FishmanandAlexander Ljungberg 18696e6bc2 Ensure CPControl -performClick unhighlights the button if the action throws. 2010-08-27 15:58:35 -04:00
Aparajita FishmanandAlexander Ljungberg 4f2914a123 Implementation of CPFont -ascender, -descender and -defaultLineHeightForFont, supporting method +metricsOfFont in CPStringDrawing and CPPlatformString, and Font Metrics Explorer test app. 2010-08-27 14:32:03 -04:00
Alexander Ljungberg 431c6522a6 Test alerts with 1 or 0 buttons defined. 2010-08-27 14:07:31 -04:00
Aparajita FishmanandAlexander Ljungberg b823eb7fe0 Fixes for Cocoa compliance 2010-08-27 14:04:28 -04:00
Klaas Pieter Annema f8ceaf62b7 set font for tableCell during nib2cib 2010-08-27 15:50:59 +02:00
Klaas Pieter Annema 213fde04fe fix CPArray+KVO addObjects inserting objects at beginning of array one by one 2010-08-27 12:06:40 +02:00
Klaas Pieter Annema ddad10b615 fix CPPredicate predicateWithFormat: throwing exception (in WebKit)
I believe the exception was caused because WebKit thought arguments was the function.Arguments.
Issue was resolved by renaming the local arguments variable to args
2010-08-26 16:55:05 +02:00
Klaas Pieter Annema f4e7386a0a fix gridColor when decoding a CPTableView
Don't default to a gray color when there is no grid color in the cib.
The tableview theme will automatically set the correct grid color.
2010-08-26 16:29:46 +02:00
Alexander Ljungberg 9a42e12985 Moved TableCibTest into the table tests folder. 2010-08-25 16:15:27 -04:00
Klaas Pieter Annema 86ee790ea1 implement missing __setSelectionIndex: 2010-08-25 15:57:35 +02:00
Klaas Pieter Annema b21eab1bf1 Improved KVC mutable indexed accessors
Refactored everything away into insertObjects:atIndexes: so all the logic is in the same place
and made it so that the _insertManySEL is the preferred selector to use. If it doesn't exist it will fall back to the _insertSEL.
2010-08-25 15:50:24 +02:00
Klaas Pieter Annema c9752195ac several CPButton theming additions
- made image and alternate image a theme property
- made image margins theme-able
2010-08-25 13:26:44 +02:00
Klaas Pieter Annema 64000215a4 Call CPObjectController designated initializer from init and initialize _observedKeys instance variable 2010-08-25 13:15:19 +02:00
Alexander Ljungberg 65d957f9f5 Fixed: an ivar was not being properly initialized in CPAlert. 2010-08-24 14:00:12 -04:00
Alexander Ljungberg aef19c3b13 Merge branch 'master' of github.com:280north/cappuccino 2010-08-24 12:30:51 -04:00
Alexander Ljungberg 9968896bbd When running CPAlert as a sheet, automatically activate the CPDocModalWindowMask window style if needed. 2010-08-24 12:14:24 -04:00
Alexander Ljungberg 1a27ae39a3 Removed CPAlert long message test from last commit since this branch already has its own long message test. Also slight clean up. 2010-08-24 11:58:36 -04:00
cacaodevandAlexander Ljungberg ee4802e513 CPAlert: Attached alerts. Added a new method -beginSheetModalForWindow: that calls -alertDidEnd:returnCode: on ending. CPAlertTest update testing it.
Fixed a bug in CPWindow where the didEndSelector was reset too early. This bug was visible only when trying to chain sheet alerts.
         Fixed a local/instance variable conflict in AttachedSheet/AppController.j
2010-08-24 11:50:44 -04:00
Klaas Pieter Annema 60dd1863b3 Implement objectsAtIndexes on _CPObservableArray to return another _CPObservableArray instance 2010-08-24 11:41:52 +02:00
Klaas Pieter Annema 71408e7c3a made CPObjectController call it's designated initializer (init) 2010-08-24 11:41:51 +02:00
Klaas Pieter Annema 659543461b Merge branch 'upstream' 2010-08-24 11:13:26 +02:00
Alexander Ljungberg 50b7f02470 Merge branch 'master' of github.com:280north/cappuccino 2010-08-23 19:45:08 -04:00
Alexander Ljungberg febdf4092e New implementation of change notifications from CPArrayController.
It is crucial that we send notification only before and after complete changes. In the middle notifications might cause observers to see or react to inconsistent data (e.g. selection indexes pointing to rows no longer present). Added some unit tests - more might be needed in the future. Fixed: before and after values when observing array controller key paths during content changes or rearranges were wrong. Fixed: the array controller sent out multiple redundant change notifications.
2010-08-23 18:53:29 -04:00
Alexander Ljungberg a3d89c8d78 Ignore table view row selection of already selected rows. This avoids potential infinite recursion caused by the explicit bindings propagation. 2010-08-23 18:51:00 -04:00
Nicholas Small c9b02603bc Don't use the deprecated .path() method in CFBundle OBJJ_PROGRESS_CALLBACK. 2010-08-23 15:48:17 -04:00
Alexander Ljungberg b9086f134a Don't include table column header graphics in the showcase - they're not really widgets which make sense standing alone. 2010-08-22 23:03:51 -04:00
Alexander Ljungberg 447c33b806 Don't layout CPAlert in layoutSubviews since it's not a real view. This avoids the theme showcase error where the CPAlert windowing code was activated by the theme descriptor setup. 2010-08-22 23:01:52 -04:00
Aparajita FishmanandAlexander Ljungberg ae47ba78cd Use [self respondsToSelector] instead of class_respondsToSelector 2010-08-22 22:06:38 -04:00
Aparajita FishmanandAlexander Ljungberg 2f51358ea0 Added documentation for the excluded mechanism. 2010-08-22 22:06:31 -04:00
Aparajita FishmanandAlexander Ljungberg c91c513b60 Proposed method of excluding themed objects from the theme showcase.
- Also added class_respondsToSelector, it was a no-brainer.

- Cleaned up trailing whitespace in CPThemeBlend.j. Woo-hoo!
2010-08-22 22:06:22 -04:00
Aparajita FishmanandAlexander Ljungberg 189d90da91 Moved theWindow to an ivar so other methods can reference it. 2010-08-22 19:03:15 -04:00
Aparajita FishmanandAlexander Ljungberg 5e20a6d9ef Sending NS_initWithCoder at the right time 2010-08-22 19:03:02 -04:00
Aparajita FishmanandAlexander Ljungberg 05edec8a8b Removed CPButton -setDefaultButton, new version of CPButton after merging with latest master. 2010-08-22 18:53:52 -04:00
Aparajita FishmanandAlexander Ljungberg 75cc0be52a Test app for default button fixes 2010-08-22 18:48:43 -04:00
Alexander Ljungberg a9e59e1e87 Fixed: in the new theme definition the table header sort images were no longer images. This would cause an exception whenever a table header was clicked such that the sort arrows needed to display. 2010-08-22 17:47:52 -04:00
Alexander Ljungberg e766a2c945 Fixed: if a CPAlert message was 3 lines or more and there was no informative text, the upper half of the CPAlert buttons would not react to clicks as the blank informative label partially covered them. 2010-08-21 17:47:03 -04:00
Alexander Ljungberg fbd5a78cf0 Don't make space for CPAlert informative text if there is none. Consider the theme size a minimum size. 2010-08-20 12:41:20 -04:00
Alexander Ljungberg f39c1a2eb8 Try to help the build bot by not calling CPAlert setWindowStyle: in init. 2010-08-20 03:01:37 -04:00
Alexander Ljungberg 5335a611a0 Use Aristo icons for CPAlert. 2010-08-20 01:55:45 -04:00
Alexander Ljungberg c06068c931 Themable CPAlert which automatically grows height-wise to accommodate all text. Adjustable icons, margins, spacing and fonts. 2010-08-19 23:03:35 -04:00
Alexander Ljungberg 62f81f2601 Remove hardcoded Aristo theme from CPAlert. New CPTheme method to get the default HUD theme style, which defaults to the default theme + "-HUD". Clean up CPAlert slightly. 2010-08-19 19:11:52 -04:00
Alexander Ljungberg 077e548219 Manual test for CPAlert which cycles through all 6 possible alert types for visual verification. 2010-08-19 19:08:25 -04:00
Alexander Ljungberg d56bc733ad Remove some accidental globals. 2010-08-18 22:01:18 -04:00
Alexander Ljungberg 8fbd24c861 Moved file globals to the top of the file. Removed a misplaced var. Eliminated empty statements. 2010-08-18 21:32:51 -04:00
Alexander Ljungberg 98049aeb78 Whitespace cleanup. 2010-08-18 17:02:22 -04:00
Aparajita FishmanandAlexander Ljungberg c9718783af Made the new theming mechanism generic (see ecbbe57) 2010-08-18 16:45:45 -04:00
Aparajita FishmanandAlexander Ljungberg bfe01badc1 Radically simplified the whole theming mechanism. Theming can now be done declaratively with less typing, better readability, easier maintenance.
Also fixed some oversights in the existing themes: text was not dimmed in disabled state for segmented controls, text was not dimmed for default buttons in disabled state in HUD (IIRC).
2010-08-18 16:45:38 -04:00
Francisco Ryan Tolmasky I 111ac84a65 Removed unecessary whitespace.
Reviewed by me.
2010-08-17 11:23:50 -07:00
Randall Luecke d7540eea84 if the new proposed selection is empty the tableview should not deselect any rows. 2010-08-17 00:01:33 -05:00
Randall Luecke 88408fc0ea Missed a couple lines in tableview custom drawing because of a merge conflict. 2010-08-16 15:10:29 -05:00
Randall Luecke 6e796d7a22 Fix for endless loop with default buttons. 2010-08-16 15:05:46 -05:00
Randall Luecke f587713795 This was terrible, real fix soon...Revert "Fix for endless loop when changing platform windows."
This reverts commit 66fcba846b.
2010-08-16 14:55:44 -05:00
Randall Luecke 66fcba846b Fix for endless loop when changing platform windows. 2010-08-16 01:26:48 -05:00
Alexander Ljungberg bdf20b0267 Merge branch 'master' of github.com:280north/cappuccino 2010-08-13 20:24:00 -04:00
Alexander Ljungberg 0292203ec0 Test that CPValueTransformerBindingOption works with CPTableColumn bindings. When run the rightmost column should read "right" and "also right" in the two initial rows. 2010-08-13 20:19:45 -04:00
Alexander Ljungberg 112ad65882 Support value transformers in CPTableColumn when using bindings. 2010-08-13 20:19:35 -04:00
Tom Robinson 6bc0880a0d Fix Doxygen executable search logic 2010-08-13 16:48:49 -07:00
Aparajita FishmanandTom Robinson 90a63e1b14 Fixes/enhancements to jake docs:
- We now have class hierarchy information! Don't remove generated headers before doxygen runs so it can generate class hierarchies. Now the headers are cleaned up separately.

- Added inline collapsible class hierarchy diagrams within each class.

- Enabled the built-in search! It's awesome!

- Changed image format to gif, dot is generated invalid png on Mac OS X.

- Explicitly turned off generation of to do and bug list.

- Turned off most warnings, most of them are useless warnings arising from the fact that we are pretending Objective-J is Objective-C.

- Doxyfile format updated to 1.7.1.
2010-08-13 15:42:43 -07:00
Tom Robinson 6ce45d32da Add comparison test for native sorting. 2010-08-13 15:40:33 -07:00
Tom Robinson 4eaf560ee6 Fixes two bugs in compareObjectsUsingDescriptors causing test to fail: extra semi-colon after while() and uninitized "result" variable.
The former masked the latter when a single sort descriptor was used.
2010-08-13 15:34:28 -07:00
Alexander Ljungberg 4c0057e66a Undoing this change since it is no longer necessary due to an alternative solution implemented by Ross Boucher. Revert "Merge commit 'c17a3533ecae63d479b285b23ac3a490ebe8bd3c'"
This reverts commit 039f2ce449, reversing
changes made to 494f39dd86.
2010-08-13 14:39:27 -04:00
Alexander Ljungberg bcb22c7e46 Remove debug output from CPArrayControllerTest. 2010-08-13 14:28:25 -04:00
Alexander Ljungberg 0683b46239 Since issue #795 has not been decided on yet, make CPArrayControllerTest pass without those changes at this time. 2010-08-13 14:18:25 -04:00
Alexander Ljungberg 61ccc39f81 Merge remote branch 'klaaspieter/fix/794-cparraycontroller-preserveselection'
Conflicts:
	Tests/AppKit/CPArrayControllerTest.j
2010-08-13 14:06:35 -04:00
Alexander Ljungberg 533e1a1846 Merge remote branch 'klaaspieter/fix/786-cparraycontroller-removeobject' 2010-08-13 14:01:47 -04:00
Alexander Ljungberg 6afe22f351 Merge remote branch 'klaaspieter/fix/784-cparraycontroller-selection' 2010-08-13 14:00:27 -04:00
Alexander Ljungberg 039f2ce449 Merge commit 'c17a3533ecae63d479b285b23ac3a490ebe8bd3c' 2010-08-13 13:56:21 -04:00
Alexander Ljungberg 494f39dd86 Closes #752. Removed some debug code which snuck in with the merge of fix-752-CPValueTransformerNameBindingOption. 2010-08-12 23:37:53 -04:00
Alexander Ljungberg c851522536 Fixed: if the CPWebView iframe was destroyed before its HTML loader timer fired, an error would occur. 2010-08-12 23:36:25 -04:00
Alexander Ljungberg 9b37ba20a3 Merge remote branch 'klaaspieter/fix-752-CPValueTransformerNameBindingOption' 2010-08-12 22:59:42 -04:00
Alexander Ljungberg 6310bfe084 Merge branch 'master' of github.com:280north/cappuccino 2010-08-12 22:50:09 -04:00
Klaas Pieter AnnemaandAlexander Ljungberg 1a9670ae9c made sure CPViewController calls viewDidLoad if it's view property is set directly 2010-08-12 22:47:59 -04:00
Randall Luecke ee9da8e31e Only call drawRect: is the view is visible. 2010-08-12 16:03:24 -05:00
cacaodevandRandall Luecke 23e9fd927c CPBox: Made CPBezelType the default type instead of none.
Slighly grayed stroke color for bezel type & fillColor for all types to better match cocoa
       Fix contentView autoresizingMask
2010-08-12 15:16:20 -05:00
Randall Luecke 22c481ff27 Implemented allKeysForObject: in CPDictionary with tests. 2010-08-12 14:18:45 -05:00
Randall Luecke 14fb769582 Removed ambiguity in CPDictionary keys type. Closes #700 2010-08-12 13:29:17 -05:00
Randall Luecke da0af13142 Added basic suppport for CPOutlineView in the nib2cib tool
Conflicts:

	AppKit/CPOutlineView.j
2010-08-12 13:11:41 -05:00
Aparajita FishmanandRandall Luecke 44fb4a9b83 -setIntercellSpacing should update the header as well as the table, per Cocoa (and common sense) 2010-08-11 23:21:30 -05:00
Randall Luecke 1e6f6879ff Run CPArrayPerformanceTest with jake test. 2010-08-11 23:17:38 -05:00
Alexander Ljungberg ba33bb56d0 Moved the visual table test for borders into the TableTest folder. 2010-08-12 00:08:43 -04:00
Aparajita FishmanandAlexander Ljungberg ab5e2dd774 Fix for issue #816 (NSTableView/CPTableView do not read selection highlight style and column resizing style) 2010-08-12 00:06:52 -04:00
Aparajita FishmanandAlexander Ljungberg 0b1b1bbe0b Fix for issue #817 (Support for alignment and line break mode in NSTextField/CPTextField) 2010-08-11 23:53:34 -04:00
Alexander Ljungberg 1aebc8942d Merge branch 'master' of github.com:280north/cappuccino 2010-08-11 23:35:26 -04:00
Alexander Ljungberg 233df3bdab Fixed: the "fix for column reordering with hidden columns" sometimes caused the table view to try to remove nonexistent data views and crash. The fix is to consider a nonexistent data view already removed and just move on. 2010-08-11 23:33:21 -04:00
Randall Luecke dd9c085ae3 Fix for new sort being unstable with a huge thanks to Shon Frazier. Reviewed by Me and Alexander Ljungberg. 2010-08-11 22:33:14 -05:00
Alexander Ljungberg 1fed798120 Fixed: CPGraphics.j was not imported anywhere so the CPScrollView borders changes didn't work. Also minor code cleanup. 2010-08-11 23:07:05 -04:00
Aparajita FishmanandAlexander Ljungberg fcf9c0bc84 Full support for all NSScrollView border types, beginnings of a new tableview tester that shows dynamic changing of border type. 2010-08-11 22:49:37 -04:00
Aparajita FishmanandAlexander Ljungberg fd9a753170 Port of NSGraphics 2010-08-11 22:49:31 -04:00
Randall Luecke 2a5f4b98ed Merge branch 'master' of git://github.com/280north/cappuccino 2010-08-11 20:30:17 -05:00
David HessandRandall Luecke ad33d1648c Patch to CPSlider to invert its value in vertical mode so that max value is represented at the top of the track instead of the bottom. 2010-08-11 20:29:46 -05:00
Alexander Ljungberg 1f784f46c7 Merge branch 'master' of github.com:280north/cappuccino 2010-08-11 20:24:29 -04:00
Randall Luecke ed52b44f8b Removed redundent methods in the tableview. Closes #822 2010-08-11 19:07:13 -05:00
Randall Luecke 4b8cc3e6d1 Table column drag view should draw lines the same color as the parent tableview. 2010-08-11 18:39:16 -05:00
Alexander Ljungberg 6b8e10cb2e Whitespace cleanup of CPShadowView. 2010-08-11 19:20:10 -04:00
Aparajita FishmanandAlexander Ljungberg 952bb4bb7c added CPShadow shadowViewEnclosingView 2010-08-11 19:18:52 -04:00
Aparajita FishmanandRandall Luecke a0bcae2404 The Cocoa default is always to draw column lines, this wasn't being set in CPTableColumnView. 2010-08-11 18:16:48 -05:00
Randall Luecke 567f54c9f9 Fix global from error in previous mergre. 2010-08-11 17:32:50 -05:00
Aparajita FishmanandRandall Luecke 66f84ede6e Fix for issue #799 (NSFont replaces LucidaGrande-Bold 13 with the theme font) 2010-08-11 17:16:44 -05:00
Aparajita FishmanandRandall Luecke 5b1ca8a7f9 Fix for issue #807 (NSTextField sets text color unconditionally, which causes theme lookup failure later) 2010-08-11 17:07:51 -05:00
Aparajita FishmanandRandall Luecke 4fc894e430 Fix for issue #820 (horizontal grid drawn incorrectly with no rows) 2010-08-11 16:58:05 -05:00
cacaodevandRandall Luecke 15356b617b DrawRowTest that was announced in the previous commit 2010-08-11 16:32:26 -05:00
cacaodevandRandall Luecke c8f6e12586 CPTableView: Implement -drawRow:clipRect: . The method is called only when a tableview subclass implements it for performance reasons.
DrawRowTest demonstrating the feature.

Conflicts:

	AppKit/CPTableView.j
2010-08-11 16:32:01 -05:00
Randall Luecke 102cc92991 Merge branch 'master' of git://github.com/280north/cappuccino 2010-08-11 16:12:43 -05:00
Randall Luecke 1e490f1796 Fix for column reordering with hidden columns. Closes #637 2010-08-11 15:59:04 -05:00
Aparajita FishmanandAlexander Ljungberg 088a5c7166 Remove extra call to _init in -initWithCoder: 2010-08-11 12:23:47 -04:00
Randall Luecke 5837533678 Use a default TableView. 2010-08-10 20:58:04 -05:00
Randall Luecke 20ec557655 Initial reorganization of CPTableView testing. 2010-08-10 20:53:43 -05:00
cacaodevandRandall Luecke b7d1dfa75f CPArray sorting: improve performance by 40% (JSC) replacing native js sort() with the merge-sort algorithm.
Test with ojunit CPArrayPerformance.j
2010-08-10 18:16:03 -05:00
Randall Luecke 33e4a082d6 Some visual changes to column dragging to make it a bit more like cocoa. 2010-08-09 18:43:11 -05:00
Randall Luecke dd49ef51d5 Merge branch 'master' of git://github.com/280north/cappuccino 2010-08-09 17:37:49 -05:00
Randall Luecke 13b2a886f3 Changed CPRect and CPPoint functions to _CG 2010-08-09 17:36:33 -05:00
Alexander Ljungberg c1dfb315a9 Merge branch 'master' of github.com:280north/cappuccino 2010-08-09 18:31:51 -04:00
Randall Luecke 96958d26c7 Accidental globals. 2010-08-09 17:22:14 -05:00
Alexander Ljungberg 8d635c7a5a Moved ArrayController1 test into the Manual folder. 2010-08-09 18:21:16 -04:00
Aparajita FishmanandAlexander Ljungberg 627c300b4a Switched to using bit mask constants 2010-08-09 18:02:40 -04:00
Aparajita FishmanandAlexander Ljungberg 00812025c2 Fix for issue #818 (NSView does not read hidden flag) 2010-08-09 18:02:32 -04:00
Alexander Ljungberg 0b21b8bab1 Merge branch 'master' of github.com:280north/cappuccino 2010-08-09 17:54:30 -04:00
Alexander Ljungberg 271bb00147 Marginally faster filter and sort in CPArrayController's arrangeObjects (4% in the performance tester.) Reduced memory usage when both a filter and a sort order are applied. Cleanup of the tester and a filter only test run. 2010-08-09 17:31:36 -04:00
Randall Luecke b346d761d8 Fix bug so we can drag items below the last child index in the outlineView. 2010-08-09 14:13:04 -05:00
Randall Luecke 21614e15b2 Draw column header lines by default. 2010-08-09 14:05:58 -05:00
Alexander Ljungberg 998c2f19cf Performance tester for CPArrayController. 2010-08-09 14:21:22 -04:00
cacaodevandAlexander Ljungberg 750cd3c258 CPComparisonPredicate :
Fixed a bug where *lhs custom_selector: nil* was always returning false.
Test nil on left and/or right with some operators.
2010-08-05 16:18:18 -04:00
Alexander Ljungberg df358ccc42 Fix failing CPPredicate unit tests: comment out test for unimplemented expressionForSubquery, finish CPExpression_unionset and fix typo in CPExpression expressionForIntersectSet. 2010-08-04 21:27:01 -04:00
Alexander Ljungberg 1b5efdfc5b Fixed with CPPredicate tests: [CPArray arrayWithObjects] don't take a final nil anymore in Cappuccino. 2010-08-04 20:50:55 -04:00
Alexander Ljungberg 63dfb8a227 CPPredicate optimization: early out in failing AND expression. 2010-08-04 20:50:36 -04:00
Alexander Ljungberg a3c0590218 Fixed with CPPredicate: [CPArray arrayWithObjects:...] should no longer be terminated with a nil in Cappuccino. 2010-08-04 20:50:07 -04:00
cacaodevandAlexander Ljungberg c694c96a32 CPPredicate & co style cleaning 2010-08-04 20:45:06 -04:00
Alexander Ljungberg 30bc304a20 Whitespace and style fixes. 2010-08-04 20:23:35 -04:00
cacaodevandAlexander Ljungberg 974cf64e1d CPPredicate &al implementation. OJUnit test. 2010-08-04 19:53:44 -04:00
cacaodevandAlexander Ljungberg fce726a031 CPScanner implementation 2010-08-04 19:48:51 -04:00
cacaodevandAlexander Ljungberg 7187ba3074 CPCharacterSet implementation 2010-08-04 19:48:27 -04:00
cacaodevandAlexander Ljungberg bfbf8fb841 Support for diacritics aware strings comparison 2010-08-04 19:48:06 -04:00
Alexander Ljungberg 4ea0d4d043 CPNull is equal to CPNull. Unit test included. 2010-08-04 16:43:04 -04:00
Alexander Ljungberg 8c13204afa Save some memory and time in CPTableViewFirstColumnOnlyAutoresizingStyle mode. 2010-08-02 23:28:40 -04:00
Alexander Ljungberg e4c79d2101 Closes #809. End editing of a text field if it is disabled or made uneditable. Manual test included. 2010-08-02 23:13:06 -04:00
Randall Luecke 90a45dca29 some fixes to default buttons to make them more cocoa compliant... 2010-08-01 20:19:26 -05:00
Alexander Ljungberg bcff25b959 Merge branch 'master' of github.com:280north/cappuccino 2010-08-01 19:15:52 -04:00
Alexander Ljungberg dff6203fb3 Closes #806. Fixed: if a selected row was removed from a table view, the selection remained and would show up again if a new row was later added. 2010-08-01 19:10:22 -04:00
Alexander Ljungberg b4dd6b670b Switch to the standard macros in _resizeAllColumnUniformlyWithOldSize as originally intended by Randy Luecke. 2010-08-01 19:06:57 -04:00
Randall Luecke f028533c07 Removed gradient stuff that has been moved to the theme. 2010-08-01 17:50:19 -05:00
Alexander Ljungberg dac61a14cd Eliminated some accidental globals in uniform table column resizing. 2010-08-01 18:10:27 -04:00
Alexander Ljungberg 6884f93d76 Fixed: after the intercell spacing commit, table column auto resizing on the first or last column would result in a total column width wider than the scroll width of the table. This would appear as the rightmost column sticking out and the table showing a horizontal scrollbar. 2010-08-01 18:06:18 -04:00
Alexander Ljungberg 17cc77e816 Clean up code in table column resizing paths in preparation for fixing it. 2010-08-01 17:14:59 -04:00
Randall Luecke 7ac59dd142 Sheets should be assigned to the platform window of the window it is attached to. 2010-07-31 20:20:18 -05:00
Alexander Ljungberg c277ae7f68 Fixed: calling CPTabView setTabViewType:CPNoTabsNoBorder before the first insertTabViewItem would cause an error. Fixed: if a tab item was added in CPNoTabsNoBorder mode, and the mode was later switched to CPTopTabsBezelBorder, that previously added tab item would have no label/tab. The solution is to maintain _labelsView in either mode; since in CPNoTabsNoBorder mode _labelsView is not in the view hierarchy anyhow the performance impact should be minimal. 2010-07-30 21:03:00 -04:00
Alexander Ljungberg 7c78753865 Fixed with CPTabView: don't remove the content and auxiliary views if the new views are the same as the old ones. This prevents flickering and needless redraws when the currently selected tab is reselected. 2010-07-30 21:02:50 -04:00
Alexander Ljungberg 9fc07ac622 Implemented NSView viewDidHide and viewDidUnhide. 2010-07-30 20:52:26 -04:00
Aparajita FishmanandRoss Boucher 364a11491d Full support for intercell spacing (issue #797) 2010-07-30 16:14:53 -07:00
Aparajita FishmanandRoss Boucher 0a26288d88 Fix for issue #804 (doxygen fails to generate class references), also did a bit of formatting cleanup in CPColor.j 2010-07-30 15:48:06 -07:00
Aparajita FishmanandRoss Boucher dcfb916d30 Fix for issue #803 (jake docs doesn't use Doxygen.app on Mac OS X) 2010-07-30 15:47:56 -07:00
Alexander Ljungberg d1c7dab356 If a CPSplitView view is collapsed through means of double click and then later restored in the same manner, preserve the original position of the divider. If the view was collapsed through dragging, double clicking to expand still positions the divider in the center of its available space. 2010-07-29 23:23:00 -04:00
Alexander Ljungberg 0e5b5c844c Split view cursor improvements. If a split view divider is at its minimum position but a collapse is possible, show that a smaller size is possible through the cursor. If a split view has a collapsed view and the cursor moves over the divider, show a 'larger size is possible' cursor. 2010-07-29 23:22:45 -04:00
Aparajita FishmanandRoss Boucher 3eea14abe4 For the methods that don't have context: in their signature, the predicate will receive undefined in the context parameter instead of nil. 2010-07-29 14:08:04 -07:00
Ross Boucher a7ca917abf Better method of expressing this condition. 2010-07-29 11:26:13 -07:00
Aparajita FishmanandRoss Boucher 9ca80df67a Cleaned up the state indicator (it was a little uneven) and centered it more horizontally in the state column. 2010-07-29 11:24:06 -07:00
Aparajita FishmanandRoss Boucher 48a89fd828 frame parameter is not being used in _initWithFrame, might as well leave it out, fixed typo in comment 2010-07-29 09:56:55 -07:00
Aparajita FishmanandRoss Boucher 1002f80617 Another fix for issue #782, uses class variable for the empty image placeholder. 2010-07-28 16:27:56 -07:00
Aparajita FishmanandRoss Boucher fc51bead8e Another try at fixing issue #782 2010-07-28 16:27:56 -07:00
Francisco Ryan Tolmasky I cea663f4eb Fix for isEqual: not being implemented in CPIndexSet.
Closes #785.

Reviewed by rossco.
2010-07-28 16:17:54 -07:00
Aparajita FishmanandRoss Boucher 8ecac8d03c Fix and test case for issue #746 2010-07-28 16:12:02 -07:00
Ross Boucher f26d2f4ebf Merge remote branch 'klaaspieter/fix-751-cpwindow-center' 2010-07-28 16:03:48 -07:00
Aparajita FishmanandRoss Boucher cb7f60aba8 Added -indexOfObjectPassingTest: and related methods 2010-07-28 15:57:47 -07:00
Ross Boucher b4dbe422ff Revert to addObject if there are no sort descriptors in insert...sortedby.
Closes #764.
2010-07-28 15:48:25 -07:00
AndreasandRoss Boucher aea19c5cd0 Add modal stylemask in nib2cib 2010-07-28 15:33:45 -07:00
Aparajita FishmanandRoss Boucher edc5542ee6 Fix for issue #748 2010-07-28 15:24:37 -07:00
Aparajita FishmanandRoss Boucher eb99b7d7ca CPSearchField fixes/enhancements to commit 5b763928fe:
- Added more documentation for -defaultSearchTemplate.

- Capitalized the text of the menu items in the default template.

- Adding a separator before no recents menu item if there are items before it.

- Updated the test app to use the default template and then modify it.

- Updated the test app to maintain the state of the custom items.
2010-07-28 15:16:04 -07:00
Aparajita FishmanandRoss Boucher 006f709d37 Fixes to commit 69273259a5:
- No longer setting the search menu template to the default, but -defaultSearchMenuTemplate was made public.

- Action and target for clear recents item is always set to CPSearchField -_searchFieldClearRecents: since that is a built-in type.

- Action and target for recents item is always set to CPSearchField -_searchFieldSearch: since that is a built-in type.

- Template menu items are copied via CPMenuItem -copy (which is now implemented), so all state is maintained.
2010-07-28 15:15:47 -07:00
Ross Boucher f5322b39bc Fix a debug mode bug in IE. Closes #768. 2010-07-28 15:13:21 -07:00
Aparajita FishmanandRoss Boucher 8702b1421f Fix for issue #777, also fixed a declared type while I was at it 2010-07-28 15:09:02 -07:00
Nicholas Small 3070634aab Make -center on a bridge window into a no-op. 2010-07-28 18:06:08 -04:00
Nicholas Small b65041a780 Merge branch 'master' of github.com:280north/cappuccino 2010-07-28 18:05:23 -04:00
Aparajita FishmanandRoss Boucher 6426c8aee2 Fix for issue #778 2010-07-28 15:04:40 -07:00
Nicholas Small 16b6753f1d Merge branch 'master' of github.com:280north/cappuccino 2010-07-28 18:03:12 -04:00
Nicholas Small b96db40e3d Merge branch 'master' of github.com:280north/cappuccino 2010-07-28 17:56:45 -04:00
Ross Boucher 7caf5fe20a Must return from this method. 2010-07-28 14:54:07 -07:00
Aparajita FishmanandRoss Boucher 44a958d3f8 -hitTest was always returning self, which did not allow any other views to receive a mouse down 2010-07-28 14:53:13 -07:00
Aparajita FishmanandRoss Boucher 4c562048dc More fixes to CPSearchField (Cocoa compliance and bugs):
- Added the ability to specify a separator in the template by using the tag CPSearchFieldSeparatorMenuItemTag.
- _recentSearches was not being initialized by -initWithCoder, moved that code into -_init.
- -setSearchMenuTemplate was not being invoked. Since having a recents menu is the default behavior in Cocoa, it should probably be the default behavior in cappuccino. To turn it off, set _maximumRecents to >= 254.
- -searchTextRectForBounds was using the wrong rect for -searchButtonRectForBounds and -cancelButtonRectForBounds, resulting in a rect that was too narrow and did not fill the space.
- Tightened up the spacing between the magnifying glass and the text to exactly Cocoa distance.
- Overhauled -
updateSearchMenu to fix some logic bugs.
- Made sure the search field becomes first responder after closing the search menu.
- Cleared the search string when clearing recent searches, this is what Safari does.
- Removed redundant invoking of -setDelegate in -initWithCoder.
- -_init has to be called last in _initWithCoder.
2010-07-28 14:53:04 -07:00
Aparajita FishmanandRoss Boucher f3b92c7445 Fixes to cacaodev/searchfield/ffb8f99603d96b903b6bb39bc4dcb15ad09465be...
- Replaced CG functions with inline _CG functions
- _canResignFirstResponder was not being initialized to YES
- -resignFirstResponder has to call super if _canResignFirstResponder == YES
2010-07-28 14:51:57 -07:00
cacaodevandRoss Boucher 675e9829bd CPSearchField: Fixes (per cocoa)
- Do not override search button action, catch mouse events in mouseDown: instead.
- Do not resign first responder on searchfield when showing the context menu
- Give more space between search button and insertion point
- Do not add search string to recents searches when typing and sendsWholeString == NO, only on enter.
- Select all text when showing the menu or after selecting a recent search in the menu
- Support custom search/cancel buttons and custom layout
- Allow images in template menu items
- Updated Test App with custom buttons
2010-07-28 14:49:02 -07:00
Ross Boucher 4c0dbda558 Merge remote branch 'klaaspieter/fix/789-observeablearray-removeobjectatindex' 2010-07-28 14:22:14 -07:00
Ross Boucher e586273a3f Fix accidental global. 2010-07-28 14:13:12 -07:00
Ross Boucher d4a0f0cd21 Merge remote branch 'klaaspieter/fix/787-cptablecolumn-editability' 2010-07-28 14:12:49 -07:00
Klaas Pieter AnnemaandRoss Boucher 8cfba4c242 only offset a nib2cib'ed textfield if it has a bezel 2010-07-28 14:09:11 -07:00
Aparajita FishmanandRoss Boucher cce13b4b45 NSMenuItem is not reading the tag for some reason 2010-07-28 14:07:45 -07:00
Alexander LjungbergandRoss Boucher 05e435633f Fixed: if a custom CPTableView header view was used for a column, such as a CPImageView, sorting by that column would cause an exception as CPTableView tried to send _setIndicatorImage: to the view. The fix is to only send the message if the view supports it. 2010-07-28 13:57:49 -07:00
Mike FellowsandRoss Boucher 6ff3fa0e52 Fix for issue #769, allow ctrl/cmd keys and F1-F12 keys to propagate to the browser unless they are blacklisted 2010-07-28 13:52:01 -07:00
Aparajita FishmanandRoss Boucher c3c996f1f7 Don't substitute the font if the textfield is not editable (a label) 2010-07-28 13:50:52 -07:00
Klaas Pieter Annema ff98a9be5a fix preserve selection in removeObjects and added unit test 2010-07-28 15:02:48 +02:00
Klaas Pieter Annema 96cef81267 Merge branch 'master' of git://github.com/280north/cappuccino 2010-07-28 13:29:16 +02:00
Klaas Pieter Annema 75ceeffab8 remove commented code from CPArrayControllerTest 2010-07-28 13:28:53 +02:00
Klaas Pieter Annema 71fffb6b68 Merge branch 'master' of git://github.com/280north/cappuccino into cparraycontroller-removeobject 2010-07-27 09:47:28 +02:00
Klaas Pieter Annema e066228015 Merge branch 'cpindexset-isequal' into arraycontroller-fixes 2010-07-27 09:23:00 +02:00
Klaas Pieter Annema 48a5d55af7 fix CPArrayController selectPrevious: and selectNext:
Also added unit-tests for canSelectPrevious, canSelectNext, selectPrevious: and selectNext:
2010-07-27 09:10:41 +02:00
Klaas Pieter Annema b9c2becd3e implement CPIndexSet isEqual: 2010-07-27 09:09:59 +02:00
Klaas Pieter Annema 24f72c0b73 Merge branch 'master' of git://github.com/280north/cappuccino into arraycontroller-fixes 2010-07-27 08:47:14 +02:00
Klaas Pieter AnnemaandRoss Boucher 90e9b86497 match CPTableView's alternating row colors with Aristo's 2010-07-26 22:48:58 -07:00
Klaas Pieter AnnemaandRoss Boucher 560ea75a25 added CPArrayController to AppKit.j 2010-07-26 22:48:40 -07:00
Klaas Pieter AnnemaandRoss Boucher 78fd972312 only reverse set the binding on end editing 2010-07-26 22:48:40 -07:00
Klaas Pieter AnnemaandRoss Boucher d947c849c8 made _accessorForKey slightly faster by inlining it as a function 2010-07-26 22:48:40 -07:00
Klaas Pieter AnnemaandRoss Boucher 8ce63a244c store accessors in a javascript object not a CPDictionary, for slight performance improvement 2010-07-26 22:48:39 -07:00
Klaas Pieter AnnemaandRoss Boucher 0306c35b54 don't copy the selection indexes in setContent: 2010-07-26 22:48:39 -07:00
Klaas Pieter AnnemaandRoss Boucher ff8e5ae42e save _replacedKeys on the class in stead of the object instance
reviewed: Ross
2010-07-26 22:48:39 -07:00
Klaas Pieter Annema acf5e5b75f call super in _CPObservableArray removeObjectAtIndex:
The current implementation calls self, which causes an infinite loop
2010-07-26 18:44:50 +02:00
Klaas Pieter Annema 4f946f267e fix CPArrayController removeObject:
removeObject: only shifted the selection, it never actually removes the object
2010-07-26 18:44:00 +02:00
Klaas Pieter Annema abfe2b4be6 Merge branch 'master' of git://github.com/280north/cappuccino 2010-07-26 16:23:28 +02:00
Klaas Pieter Annema bb3c08ce0b add CPArrayController test 2010-07-26 14:04:26 +02:00
Klaas Pieter Annema 138888e620 implement CPArrayController insertObject:atArrangedObjectIndex: 2010-07-26 14:04:05 +02:00
Nicholas Small 4e1b429913 Merge branch 'master' of github.com:280north/cappuccino 2010-07-22 15:41:28 -04:00
Randall Luecke 51f780b5f5 Merge branch 'master' of github.com:280north/cappuccino 2010-07-22 00:21:51 -05:00
Randall Luecke cffbf86351 TableView theming 2010-07-22 00:21:02 -05:00
Ross Boucher 709a9b3c61 Merge remote branch 'klaaspieter/fix-758-cpdate-isequal' 2010-07-21 15:04:10 -07:00
Ross Boucher c35621b669 Merge remote branch 'klaaspieter/fix-756-cpstring-isequal' 2010-07-21 15:03:43 -07:00
Alexander LjungbergandRoss Boucher 4d1baac4db Fixed: first clearing a \r keqyEquivalent from one button and then setting it on another would result in an exception. 2010-07-21 14:57:52 -07:00
Alexander LjungbergandRoss Boucher 474623feb3 Added support for punctuation based key equivalents such as Cmd-' or Cmd-;. Fixed: [event characters] would contain Þ when Cmd-' was pressed and º for Cmd-; since the key codes for punctuation do not match the ASCII codes and String.fromCharCode does not work. Manual test included. 2010-07-21 14:52:05 -07:00
Klaas Pieter Annema c17a3533ec fix #764
Array controller inserts object in wrong arranged object position if there are no sort descriptors defined
2010-07-20 14:59:18 +02:00
Ross Boucher 85f3691432 Don't add a "Shift" if it's not required. 2010-07-19 16:27:44 -07:00
Klaas Pieter Annema 2ae8d25d18 don't use === for date equality checking
Apparently this will return false for equal dates, reverted the actual equality check to what was already in Cappuccino before my fix !(date < otherDate || date > otherDate)
2010-07-19 13:10:15 +02:00
Nicholas Small 780bdc4421 Generate accessors for _CPSegmentInfo. 2010-07-18 03:05:31 -04:00
Randall Luecke a2e6f8f964 Initial theming of TableView header. 2010-07-15 22:32:00 -05:00
Klaas Pieter Annema 564668587c fix CPDate isEqual: and isEqualToDate: 2010-07-15 14:42:48 +02:00
Klaas Pieter Annema 023cf46041 check for nil in CPString isEqual: 2010-07-15 14:39:24 +02:00
Klaas Pieter Annema 36bb41a945 implemented isEqual: on CPString 2010-07-15 12:49:52 +02:00
Randall Luecke 0cbdb3b2d1 Fix for redrawing issues in tableview. Closes #627 2010-07-12 21:14:48 -05:00
Randall Luecke 70f2d86b58 Fixes for adding and removing columns to the tableview after the tableview has already been displayed... There are still issues though. 2010-07-12 20:45:30 -05:00
Klaas Pieter Annema 914175de70 If CPValueTransformerNameBindingOption contains an existing class, allocate and use it in CPKeyValueBinding 2010-07-12 15:41:00 +02:00
Randall Luecke 7696b30067 Added tests for CPFormatter and Foundation import. 2010-07-11 16:57:17 -05:00
Klaas Pieter Annema 478b5eaba3 make sure CPWindow center never puts it's window origin at a negative coordinate 2010-07-09 12:46:54 +02:00
Klaas Pieter Annema 52f0c0f587 Merge branch 'master' of git://github.com/280north/cappuccino 2010-07-08 16:27:15 +02:00
Randall Luecke 2a4d3507b8 Implementation fix for CPFormatter to conform to documentation. 2010-07-07 19:49:16 -05:00
Randall Luecke 78a75924de selectedRowIndexes should return a copy, closes #605 2010-07-07 16:46:48 -05:00
Randall Luecke a34dfee752 CPFormatter implementation. 2010-07-06 22:43:30 -05:00
Randall Luecke 5ca9b4f370 Merge branch 'master' of git://github.com/280north/cappuccino 2010-07-06 22:43:15 -05:00
Randall Luecke 2a2b320be3 Added image support for overflow toolbaritems. Also disabled the menu items if the toolbar is disabled. 2010-07-06 22:37:58 -05:00
Nicholas Small 071ab7d555 Only use CPView -display* methods while in DOM. 2010-07-02 14:58:23 -04:00
Klaas Pieter Annema 9738bbfbe5 Merge branch 'master' of git://github.com/280north/cappuccino 2010-07-02 09:25:27 +02:00
Nicholas Small e385321f95 CPArrayController -selectedObjects returns a CPObservableArray. 2010-06-30 22:28:02 -04:00
Nicholas Small 21a9ae4c45 Make CPTableView work with selectionIndexes binding. 2010-06-30 12:03:03 -04:00
Nicholas Small 6a689dc3df Fix for asking the wrong object for -_replacementKeyPathForBinding: when creating a new binding. 2010-06-30 12:00:20 -04:00
Klaas Pieter Annema af0ca52739 made CPViewController equal cappuccino master 2010-06-30 11:50:53 +02:00
Klaas Pieter Annema 83ea50a836 don't send windowWillLoad and windowDidLoad if the window is not loaded from cib 2010-06-30 11:41:22 +02:00
Klaas Pieter Annema 2022eb5c12 Merge branch 'master' of git://github.com/280north/cappuccino 2010-06-30 11:19:23 +02:00
Klaas Pieter Annema 6b132c4d3b added check for nil in CPIndexSet isEqual 2010-06-30 11:15:38 +02:00
Nicholas Small f34775b038 CPAttributedString should not call its own -beginEditing or -endEditing. 2010-06-29 14:02:37 -04:00
Klaas Pieter Annema f73d8a55de implemented isEditable nib2cib support for CPTableColumn 2010-06-29 17:47:36 +02:00
Klaas Pieter Annema 3d39bf8720 Merge branch 'master' of git://github.com/280north/cappuccino 2010-06-29 11:27:33 +02:00
Randall Luecke 9a302328c6 Move the new close button a little to the right to confrom with the Aristo art. 2010-06-26 23:35:33 -05:00
Randall Luecke cdb1ac32fa Use the new Aristo HUD window art. 2010-06-26 23:22:24 -05:00
Alexander LjungbergandRandall Luecke 74af0dc93a Fixed: Shift + Arrow Keys in allowsMultipleSelection CPTableViews did not expand the selection anymore after the recent key binding updates. 2010-06-26 00:10:30 -05:00
Alexander LjungbergandRandall Luecke 2da1dc31fb Simplify CPCollectionView keyboard selection code, eliminate some redundancy. 2010-06-26 00:10:21 -05:00
Alexander LjungbergandRandall Luecke 6b55c81462 Fixed: Shift + Arrow Keys in allowsMultipleSelection CPCollectionViews did not expand the selection anymore after the recent key binding updates. 2010-06-26 00:10:12 -05:00
Alexander LjungbergandRandall Luecke 07630964c1 Reverse bindings support for CPCollectionView selectionIndexes. This enables binding a CPCollectionView's selectionIndexes to a CPArrayController. 2010-06-26 00:09:54 -05:00
AndreasandRoss Boucher a6b7d456f4 Add isLoaded to CFBundle and CPBundle 2010-06-23 20:11:05 -07:00
Ross Boucher 7c5a07f709 Fix the issue where CPSecureTextField would sometimes cause all other text fields to go crazy afterwards. 2010-06-23 19:58:43 -07:00
Ross Boucher 7e25166ce1 Revert the fixed frame size assumption for now. 2010-06-23 19:13:56 -07:00
Klaas Pieter Annema 10df31cbf9 made isEqual: work on CPIndexSet and updated unit tests 2010-06-22 07:47:30 +02:00
Randall Luecke 10c067e44f When dragging over a tableview row we should jump to the next row at the bottom 30% of the row, not 50%... otherwise it gets really really bad with large row heights. 2010-06-21 22:32:18 -05:00
Scott KyleandRoss Boucher f81e97726a Fixed setName: in CPImage to return BOOL as in Cocoa 2010-06-21 13:23:27 -07:00
nciagra 8f040d6ff1 Fixed a couple of Unix key bindings. 2010-06-21 13:53:17 -04:00
Alexander LjungbergandRoss Boucher 32fb13a9a9 Fixed: long titles in CPAlert buttons would be cut off. Fix is to use the standard 80 pixels width as a minimum width only. 2010-06-19 18:26:19 -07:00
Alexander LjungbergandRoss Boucher 4b86115d30 Set the alert default button using the CPCarriageReturnCharacter key equivalent to match the recent Cappuccino change for default buttons. 2010-06-19 15:42:29 -07:00
Alexander LjungbergandRoss Boucher 12a49d0ee1 CPAlert informative text support. 2010-06-19 15:41:15 -07:00
nciagra b37f5b4143 Fix CPResponderTest. 2010-06-18 14:18:29 -04:00
nciagra cbb9602f9e Better caching of key bindings. 2010-06-18 11:50:33 -04:00
nciagra 997a305d35 Added CPKeyBinding for a dynamic key binding system. 2010-06-18 10:40:15 -04:00
nciagra f09193ce07 Properly differentiate between special keys and normal keys in key handlers. 2010-06-17 00:17:52 -04:00
nciagra 96fc34c00e CPResponder -interpretKeyEvents: will only call -insertText: if the Command and Control keys are not being held. 2010-06-16 22:03:31 -04:00
nciagra bd06b8a867 Modifier keys will fire flagsChanged: instead of keyDown: and keyUp:, like Cocoa does. 2010-06-16 22:02:40 -04:00
Randall Luecke 7414d1407f Moved tracking of last selected row index to selectRowIndexes: in tableview. 2010-06-16 13:59:25 -05:00
Ross Boucher 19d5431f60 Revert "slightly delay triggering the action in CPControl performClick: to make sure the click is always visible"
This reverts commit eaf4fa240f.
2010-06-16 08:54:30 -07:00
Alexander LjungbergandRoss Boucher f2c01cbbbd In CPUndoManager, handle the edge cases if an object changes from being an Objective-J object to being just a JS object. Also handle the case where an Objective-J object could theoretically compare equal to nil - CPNull isEqual:. 2010-06-16 08:50:42 -07:00
Alexander LjungbergandRoss Boucher c807358216 Support non Objective-J objects in CPUndoManager's no-op check for auto undo. 2010-06-16 08:50:34 -07:00
Alexander LjungbergandRoss Boucher 685c3c9853 Don't add no-ops to the undo stack when using automatic undo manager mode. This is necessary when used together with bindings since controls issue reverse binding updates whenever editing ends, which would add a 'do nothing' undo entry on the stack in cases where nothing changed. 2010-06-16 08:50:27 -07:00
Alexander LjungbergandRoss Boucher db3514a2c1 Only allow a single window frame animation at a time; stop the previous animation before starting a new one. This allows e.g. a sheet animating open to 'turn around' and animate right back out. Fixed: if a sheet was closed before it finished animating open, for example by hitting a keyboard equivalent immediately, CPWindow would crash with "Uncaught TypeError: Cannot read property 'sheet' of null". 2010-06-16 08:46:54 -07:00
Aparajita FishmanandRoss Boucher 6a43c544eb Added support for reading max rows/columns from cib 2010-06-16 08:32:14 -07:00
Ross Boucher 1b174b86ca Buttons should also be re-centered after their height is changed in nib2cib. 2010-06-16 08:14:04 -07:00
Klaas Pieter Annema f40fc321fe Make the window perform it's defaults button's key equivalent after the default keyDown messages are handled 2010-06-16 14:17:58 +02:00
Klaas Pieter Annema eaf4fa240f slightly delay triggering the action in CPControl performClick: to make sure the click is always visible 2010-06-16 14:16:17 +02:00
Ross Boucher 17a8be1ae6 Return the actually last selected row in CPTableView.
Closes 716.
2010-06-15 19:20:48 -07:00
Aparajita FishmanandRoss Boucher 16be03b162 If first segment is enabled and mode is one-only, _selectedSegment is correctly set to 0 2010-06-15 19:11:31 -07:00
Ross Boucher 2f58517ce5 Request headers should be set after the request is re-opened. Closes #701. 2010-06-15 09:29:04 -07:00
Francisco Ryan Tolmasky I 9a3c2d5311 Fix for scrolling affecting background windows with NativeHost.
Reviewed by me.
2010-06-12 18:33:59 -07:00
Ross Boucher fed39694f6 Improve the handling of key window's losing their status. 2010-06-12 18:23:51 -07:00
Francisco Ryan Tolmasky I bb659e3c06 Make fast enumeration more debugging friendly.
Reviewed by me.
2010-06-12 17:14:57 -07:00
Alexander LjungbergandRoss Boucher 5c5412db67 Make didChangeValueForKey work even if willChangeValueForKey was not called. 2010-06-11 14:08:07 -07:00
Alexander LjungbergandRoss Boucher 1c35bd22f8 Don't test keyCodes directly in CPResponder now that we have proper key equivalent characters. 2010-06-11 12:05:31 -07:00
Alexander LjungbergandRoss Boucher c28222e04d Test CPResponder's interpretKeyEvents in preparation for rewrite. 2010-06-11 12:05:23 -07:00
Alexander LjungbergandRoss Boucher 854481e395 Fixes #710. Treat \r and \n key equivalents as the same key (return). 2010-06-11 10:19:07 -07:00
Alexander LjungbergandRoss Boucher 44555ac724 UTF compatible CFData base64 string encoder and decoder. Use it for CPButton key equivalent archiving. Also ordered CPText.j constants by value and removed the empty CPText class definition as it caused errors with nib2cib. Fixed: the key equivalent for forward delete (CPDeleteFunctionKey, \uF728) was transformed to '(' (\u0028) when archived and unarchived. 2010-06-11 09:39:19 -07:00
Alexander LjungbergandRoss Boucher dcec14decd Fixed: delete (backspace) and forward delete were switched as compared to Cocoa. Fixed: delete could not be used as a key equivalent without a modifier. 2010-06-11 09:37:47 -07:00
Randall Luecke f62d81e79f Fix for nib2cib breaking with an emptry class implementation. 2010-06-10 22:37:52 -05:00
Derek HammerandRandall Luecke 9ff056f073 Making the DisclosureButton a little more subtle. Adding shadow to the disclosure buttons. 2010-06-10 18:21:51 -05:00
Ross Boucher 1edb0bcc4a Fix for null key equivalents. 2010-06-10 16:14:22 -07:00
Scott KyleandRandall Luecke 1899250a53 Semicolons are nice... 2010-06-10 16:42:28 -05:00
Scott KyleandRandall Luecke 443e23e348 Without the commas, these create global variables 2010-06-10 16:42:19 -05:00
Ross Boucher 1e6595fca7 Slight switch statement change so that nil/0 are treated equivalently. 2010-06-10 13:29:47 -07:00
Alexander LjungbergandRoss Boucher 5ed475eedd Slightly faster _couldBeKeyEquivalent (1% of runtime in 3000 calls). Performance test included. 2010-06-10 10:57:42 -07:00
Alexander LjungbergandRoss Boucher 17669fd09d Optimized _triggersKeyEquivalent for a 6.5% performance gain in the CPKeyEquivalentPerformance test. 2010-06-10 10:56:02 -07:00
Alexander LjungbergandRoss Boucher 51825db716 Fixed: [CPDate description] did not generate a correct date for users in timezones with a negative timezone offset. 2010-06-10 10:49:49 -07:00
Ross Boucher 421ae6b316 Make CPButton archive its key equivalents, and make nib2cib support the feature. 2010-06-10 10:41:15 -07:00
Francisco Ryan Tolmasky I 3c98ed78ee Merge branch 'master' into @each
Conflicts:
	Objective-J/Preprocessor.js
	Objective-J/Runtime.js
2010-06-09 16:29:57 -07:00
Aparajita FishmanandRoss Boucher 9ab446b790 Added image alignment support to CPImageView, CPWindowController always loads a cib from the main bundle for consistency with Cocoa, CPApplication modified to explicitly load the About panel cib from the Framework bundle 2010-06-09 14:24:00 -07:00
Ross Boucher c65e3d4e6d Move the bindings test to the manual folder. 2010-06-09 14:23:27 -07:00
Ross Boucher 10fad00c1e Merge remote branch 'aljungberg/keyequivalents-merge' 2010-06-09 13:42:57 -07:00
Tom Robinson 478f2d8134 Name Objective-J allocators to get correct WebKit heap snapshot reports. 2010-06-09 13:16:45 -07:00
Thomas InghamandRoss Boucher a49b01d396 Added missing asset. 2010-06-08 19:29:11 -07:00
Alexander Ljungberg c26ebe0bd2 Added support for menu key equivalents such as Escape or Cmd-Delete. Refactored code to recognize key equivalents for reuse between CPMenu and CPButton. Added unit tests for CPMenu key equivalents. 2010-06-07 19:09:15 -04:00
Alexander Ljungberg 381a44148e Special keys such as backspace and escape can now be used as key equivalents through checking for their unicode representations in [CPEvent characters]. This replaces the earlier raw key code approach. 2010-06-07 19:09:10 -04:00
Alexander Ljungberg c1f16de441 Defined function and special key constants. 2010-06-07 19:09:01 -04:00
Alexander Ljungberg 4a048657c5 If a button is named "Cancel" in a CPAlert window, give it the 'escape' key equivalent. 2010-06-07 19:08:50 -04:00
Alexander Ljungberg 44f5086600 Key equivalents for CPButton. 2010-06-07 19:08:44 -04:00
Klaas Pieter Annema ddddc3330d Merge branch 'master' of git://github.com/280north/cappuccino 2010-06-07 11:09:41 +02:00
Randall Luecke 39ba9b9a4f setSeletable now works in CPTextField. Closes #690 2010-06-06 16:26:51 -05:00
Alexander LjungbergandRandall Luecke bdb36f35cf Fixed: the actual delegate method definition somehow didn't make it into the change enabling outlineView:shouldEditTableColumn:item: for outline view inline editing. This commit predefines all CPOutlineView delegate methods. 2010-06-06 16:07:50 -05:00
Ross Boucher 0c9b4da473 Don't supress exceptions in the backtrace decorator, add an exception supressing decarator. 2010-06-06 12:57:45 -07:00
Stephen IerodiaconouandRoss Boucher 935f1084d6 Javascript Date object returns month between 0 and 11 2010-06-06 12:05:11 -07:00
Saikat ChakrabartiandRoss Boucher c8759babae Adding checks for existence of DOM when calling CPPlatformWindow+DOM-only methods
Conflicts:

	AppKit/CPWindow/CPWindow.j
2010-06-06 11:48:15 -07:00
Francisco Ryan Tolmasky I ab3d648244 Fix for browser:acceptDrop:atRow:column:dropOperation: not being called if browser:validateDrop:proposedRow:column:dropOperation: is implemented.
Reviewed by me.
2010-06-04 19:21:43 -07:00
Randall Luecke 57dc0460a3 Fixed theme state for CPBrowser. 2010-06-03 21:09:18 -05:00
Randall Luecke d5ee07fe1b CPControl should not be allowed to performClick: if it's disabled. 2010-06-02 20:43:09 -05:00
Klaas Pieter Annema 89e3618d85 Merge branch 'master' of git://github.com/280north/cappuccino 2010-06-02 15:37:11 +02:00
Randall Luecke 162381a73f Removed worthless variable in the collectionview. 2010-06-01 19:16:02 -05:00
Klaas Pieter Annema 08db857334 Merge branch 'master' of git://github.com/280north/cappuccino 2010-06-01 10:16:11 +02:00
Randall Luecke bb651d0c70 Added multiple selection support to the collectionview. 2010-06-01 01:53:26 -05:00
klaaspieterandRandall Luecke d9c094f644 call tableview doubleclick action even if target is nil (action will travel down the responder chain)
Conflicts:

	AppKit/CPTableView.j
2010-05-31 19:14:54 -05:00
Klaas Pieter Annema 32040bdd7e Merge branch 'tableview-doubleclick'
Conflicts:
	AppKit/CPTableView.j
2010-05-31 15:44:24 +02:00
Klaas Pieter Annema 43f0e43de7 call tableview doubleclick action even if target is nil (action will travel down the responder chain) 2010-05-31 15:41:52 +02:00
Klaas Pieter Annema 5122b15ffb Merge branch 'windowcontroller-loadwindowfix' 2010-05-31 13:48:23 +02:00
Klaas Pieter Annema 468d8e7c33 call windowWillLoad and windowDidLoad if the window is set directly from the initializer 2010-05-31 13:45:51 +02:00
Klaas Pieter Annema 93b1d1e591 Merge branch 'master' of git://github.com/280north/cappuccino 2010-05-31 10:34:52 +02:00
Ross Boucher 1642149228 Missing #include had broken the slider color picker. 2010-05-28 12:45:15 -07:00
Ross Boucher 8fd564b034 Minor cleanup to the current test cases. 2010-05-28 10:54:45 -07:00
Ross Boucher 7c3f94dd87 Merge remote branch 'klaaspieter/bindings-fixes' into bindings
Conflicts:
	AppKit/CPControl.j
	Foundation/CPValueTransformer.j
2010-05-28 10:23:47 -07:00
Klaas Pieter Annema eacd408ce8 Fixed a typo in CPObjectController 2010-05-27 15:23:09 +02:00
Klaas Pieter Annema 084da71420 exposed more bindings on CPControl 2010-05-27 15:22:40 +02:00
Alexander Ljungberg 3fa47ee9ec Fixed: [_CPImageAndTextView setDimsImage] wasn't working right due to checking if a non existent variable equalled the current value. 2010-05-26 20:09:01 -04:00
Alexander Ljungberg e811895570 Fixed: CPObjectController keyPathsForValuesAffectingX typos. 2010-05-26 20:06:32 -04:00
Alexander Ljungberg 47e890b8e1 Fixed table row drag view when using bindings. 2010-05-26 20:02:12 -04:00
Alexander Ljungberg f2bb27dc32 Fixed: [CPArray isEqualToArray:nil] threw an exception instead of returning NO. 2010-05-26 19:54:20 -04:00
Alexander Ljungberg ef9d2d1775 Reverse update value binding when control editing stops, not only when the action fires. This causes tabbing out of a text field to update the binding source. Based on the description of the bindings option NSContinuouslyUpdatesValueBindingOption this is the right thing to do: if NSContinuouslyUpdatesValueBindingOption is on, update on every character; "otherwise the update is made only when the user interface item resigns as the responder." 2010-05-26 19:51:51 -04:00
Alexander Ljungberg be13a14330 Hack to make [textField bind:CPValueBinding ...] work. Without this, any observed change leads to a [textField setValue:X forKey:"value"] which in turn leads to a direct ivar access changing the value in textField._value. This means the text field has no idea the value changed and it doesn't update to show the new text. I'm not sure what the right solution should be here. It looks like _replacementKeyPathForBinding should play into this and change the end result to [textField setValue:X forKey:"objectValue"] which would work fine. But currently _replacementKeyPathForBinding applies to the observed key path, not the bound one. 2010-05-26 19:51:28 -04:00
Alexander Ljungberg 45a2bcb71a Fixed bindings problems where 'nil' would be transformed into @"". Also, CPIsNilTransformerName and its inverse couldn't work because any nil value was immediately returned without transformations being applied. Full complement of unit tests included, based on Cocoa empirical testing.
Fixed with CPKeyValueBinding: the CPValueTransformerNameBindingOption option would cause an exception due a missing import.
2010-05-26 19:50:35 -04:00
Alexander Ljungberg 48fb660e66 The problem with initialize in fb5950c82d0124bdebb6e03cb4509306ef4161c8 turned out to be caused by a Cappuccino bug with class methods and arguments named 'name'. Renaming the argument solved the problem so I reverted the initialize change. This fix also fixes valueTransformerForName. 2010-05-26 19:49:49 -04:00
Alexander Ljungberg 218919a8ba Fixed: exposed bindings on CPObject would not appear in CPObject subclasses. 2010-05-26 19:48:27 -04:00
Alexander Ljungberg 79ed04e403 Fixed: including CPValueTransformer.j causes an infinite loop due to the recent Objective-J (mis?) behavior that every class has to inherit from CPObject. Also, the transformer map failed to initialize properly with the existing setup code for reasons which were not immediately clear. Moving the initialization to a regular + initialize method eliminated the problem.
Fixed: CPKeyValueBinding.j would throw an exception if a named value transformer option was specified, due to CPValueTransformer.j not being imported.
2010-05-26 19:47:45 -04:00
Alexander Ljungberg 3c995fe17b Fixed: the array controller remove method mapped selection indexes to the content array instead of the arranged objects, leading to the wrong objects being removed as filters and sort descriptors were effectively ignored. 2010-05-26 19:45:13 -04:00
Alexander Ljungberg 5ff8ddf5f3 Fewer bindings debug log messages. 2010-05-26 19:44:14 -04:00
Alexander Ljungberg 8b2350fb22 Optimized table data loading when using bindings for the cell values. A special code path in the CPTableColumn's prepareDataView:forRow: method turns a O(n) operation into O(1) where n is the number of items in the model array. 2010-05-26 19:42:59 -04:00
Alexander Ljungberg 15be647c16 Fixed: the CPArrayController code to remove out of bounds selections failed to remove the last selected item if the new arrangedObjects array was empty. 2010-05-26 19:42:40 -04:00
Alexander Ljungberg 8a8af0e4a9 Fixed: CPArrayController could get out of bounds selections if a call to rearrangeObjects caused objects to disappear from the arranged set. 2010-05-26 19:41:34 -04:00
Alexander Ljungberg 4ff89eab04 Fixed: CPArrayController would throw out of bounds exceptions when its content array was shortened and items at the end were selected.
Extended avoid empty selection support so that when the last item is selected and deleted, the (previously) second to last item is selected instead. Works as expected with multiple selections.
2010-05-26 19:40:55 -04:00
Alexander Ljungberg ec032cb739 Performance fix: willChange and didChange for CPArrayController's selectionIndexes were sent doubly. 2010-05-26 19:40:24 -04:00
Alexander Ljungberg 2b287a85e5 CPArrayController now pushes new selections to the bound model for selectionIndexes. Using this, support for selectsInsertedObjects was added.
This commit also fixes a performance problem where calling setSelectionIndexes with a selection equal to the one already active caused a selection update.
2010-05-26 19:39:42 -04:00
Alexander Ljungberg 6ea2b4e0e2 Fixed: the CPArrayController addObject: optimization for fast index updates would never fire with a nil _filterPredicate, causing rearrangeObjects to be called needlessly. 2010-05-26 19:39:09 -04:00
Alexander Ljungberg f7e2e9c2ee Fixed: the _CPObservableArray init method used by CPArrayController did not properly initialize _observationProxies.
Fixed: _CPObservableArray's insertObject:atIndex: caused an infinite loop.
2010-05-26 19:37:28 -04:00
Alexander Ljungberg 5463e5ca55 Fixed: CPArray insertObject:inArraySortedByDescriptors: did not return the index into which the object was inserted. This would have broken CPArrayController's addObject code. 2010-05-26 19:36:26 -04:00
Alexander Ljungberg 396d4218f0 Fixed: CPArrayController keys ContentArray, ArrangedObjects, Selection, SelectionIndex, SelectedObjects, CanRemove and CanSelectNext could not be observed properly because their dependency declarations had a repeated typo. 2010-05-26 19:30:06 -04:00
Alexander Ljungberg e3a07845d4 Implemented CPTableView clickedRow for use in double-action. 2010-05-26 19:24:36 -04:00
Alexander Ljungberg 341a42bddd DataSource delegate method tableView:objectValueForTableColumn:row is optional if bindings are used to provide data for the table view. 2010-05-26 19:20:38 -04:00
Alexander Ljungberg 573444e640 Removed a bindings console.log statement incompatible with browsers without a debug console. 2010-05-26 19:14:03 -04:00
Alexander Ljungberg ed9c6d7959 Added reverse sort tests for CPArray insertObject:inArraySortedByDescriptors:. 2010-05-26 19:11:58 -04:00
Alexander Ljungberg ed2c65dd6f Merge branch 'master' of git://github.com/280north/cappuccino into bindings-merge
Conflicts:
	AppKit/CPTableView.j
	Foundation/CPArray+KVO.j
	Foundation/CPArray.j
2010-05-26 19:05:04 -04:00
cacaodevandRoss Boucher 0062caafdf CPObject -implementsSelector: 2010-05-26 10:06:49 -07:00
Stephen IerodiaconouandRoss Boucher b98f0b1427 Apply style rules to Foundation 2010-05-26 08:53:05 -07:00
Stephen IerodiaconouandRoss Boucher b6a3d2b283 Remove import of deprecated CPLog.j
Remove deprecated CPLog.j
2010-05-26 08:52:59 -07:00
Stephen IerodiaconouandRoss Boucher 0d848e3d93 Add test on self in init of CPAttributedString 2010-05-26 08:52:46 -07:00
Stephen IerodiaconouandRoss Boucher 065197980b CPCoder typo fixes 2010-05-26 08:51:58 -07:00
Thomas InghamandRoss Boucher 2a36488db7 Added new artwork and theme style for the button.
Matching fonts to segctl.
2010-05-26 08:51:36 -07:00
Klaas Pieter Annema 3cd44284c4 - added CPValueTransformer to Foundation.j
- made CPValueTransformer import Foundation objects directly
- gave the build in transformers CPValueTransformer as superclass
2010-05-26 16:46:44 +02:00
Klaas Pieter Annema bc0fa6a62e made removeObject on _CPKVCArray work properly 2010-05-26 16:45:55 +02:00
Klaas Pieter Annema 51c90223fc exposed enabled binding on CPControl and made sure CPControl's bindings are only exposed once 2010-05-26 16:44:55 +02:00
Klaas Pieter Annema df1b56becf Merge branch 'master' of git://github.com/280north/cappuccino 2010-05-26 11:58:49 +02:00
Tom Robinson 5a77c19791 Silence tools output during tests (press, flatten, capp gen) 2010-05-25 16:24:29 -07:00
Tom Robinson eae3270385 Add bcomm hook to LoadTimeTest 2010-05-25 14:09:10 -07:00
Randall Luecke daee101005 Merge branch 'master' of git://github.com/280north/cappuccino 2010-05-25 14:05:24 -05:00
Klaas Pieter AnnemaandRandall Luecke b32d503d65 implemented CPTableColumn isHidden nib2cib support 2010-05-25 14:03:14 -05:00
Klaas Pieter AnnemaandRandall Luecke ca7af88c59 - updated tablecolumn nib2cib to support new row selection theme state
- nib2cibed the MainMenu.xib in the tablecib example to update it's cib to the changes
2010-05-25 14:03:04 -05:00
Klaas Pieter AnnemaandRandall Luecke 6bd8e96ac0 fixed a bug where the table header would attempt to set content inset on a _CPImageAndTextView 2010-05-25 14:02:52 -05:00
Klaas Pieter AnnemaandRandall Luecke d06d69966b used content inset in stead of frame offset to properly place the table header text 2010-05-25 14:02:41 -05:00
Klaas Pieter AnnemaandRandall Luecke 004829ac9e table header view nib2cib updates 2010-05-25 14:02:30 -05:00
Randall Luecke 0009603098 removed the border from _CPCornerView (Aristo)
Conflicts:

	Tests/Manual/TableCibTest/Resources/MainMenu.cib
2010-05-25 14:01:42 -05:00
Klaas Pieter AnnemaandRandall Luecke 5479c77ae6 changed the table header view image height to 23.0 2010-05-25 14:00:46 -05:00
Klaas Pieter AnnemaandRandall Luecke 1f97616f3c override default IB tableview grid colors with aristo's 2010-05-25 14:00:34 -05:00
Klaas Pieter AnnemaandRandall Luecke e65fcdab42 - changed default dataview styling to aristo
- updated nib2cib support for CPTableColumn
2010-05-25 14:00:22 -05:00
Klaas Pieter AnnemaandRandall Luecke 428f5a656d changed default table view alternating row colors to aristo 2010-05-25 14:00:10 -05:00
Klaas Pieter AnnemaandRoss Boucher 0315ad38f9 - fixed CPKeyedUnarchiver decodeBytesForKey attempting to access nil (or undefined) data
- improved CPSearchField nib2cib support
2010-05-25 11:48:03 -07:00
Klaas Pieter AnnemaandRoss Boucher 6c1a6a2033 made _sendPartialString send it's action down the responder chain 2010-05-25 11:47:52 -07:00
Klaas Pieter AnnemaandRoss Boucher 2a630a7210 made CPDictionary call [super valueForKey:] on keys prefixed with @ 2010-05-25 11:40:45 -07:00
Klaas Pieter Annema 528203d8e5 made CPDictionary call [super valueForKey:] on keys prefixed with @ 2010-05-25 20:37:00 +02:00
Klaas Pieter Annema fd5a0cc468 Merge branch 'master' of git://github.com/280north/cappuccino 2010-05-25 11:23:18 +02:00
Randall Luecke 359a29874b Return a copy instead of the array itself. 2010-05-24 22:44:14 -05:00
Randall Luecke f9da7f73b3 Added missing pathComponents method to CPURL. 2010-05-24 21:59:37 -05:00
Alexander LjungbergandFrancisco Ryan Tolmasky I 49ae82d96a Fixed: CPToolbar validateVisibleItems was called validateVisibleToolbarItems. 2010-05-24 15:53:12 -07:00
Francisco Ryan Tolmasky I fbd23fb2c3 Removed unecessary var.
Reviewed by me.
2010-05-24 15:45:54 -07:00
Paul BaumgartandFrancisco Ryan Tolmasky I 252b258159 fix CFDictionary.containsValue and CFDictionary.countOfValue and add tests to prove it 2010-05-24 15:45:21 -07:00
Alexander LjungbergandFrancisco Ryan Tolmasky I dfcef3ca2d Fixed: [CPPopUpButton itemTitles] didn't work. 2010-05-24 15:45:07 -07:00
Thomas InghamandRoss Boucher 3d4a33d373 Re-preflight on the image assets resulting in 24px tall images in each case. This is done by cutting the top edge close (well into the aliased edge on top.)
Added defs for the horizontal and vertical sliders.
2010-05-24 15:31:04 -07:00
Ross Boucher 28397e672e fix a misnamed variable.
closes #673.
2010-05-24 11:28:57 -07:00
Alexander LjungbergandRoss Boucher bbbf439028 Fixed: contentBounds not var'ed in _verticalScrollerDidScroll. Whitespace cleanup. 2010-05-24 11:21:23 -07:00
Alexander LjungbergandRoss Boucher 3c5dab1f34 Implemented CPCoding for CPButton imageDimsWhenDisabled. Fixed a problem where setImageDimsWhenDisabled:NO would not cause a redraw even if the image was previously dimmed. 2010-05-24 11:17:25 -07:00
Saikat ChakrabartiandRoss Boucher e8499e1751 Adding grab/grabbing cursors for Firefox. 2010-05-24 10:15:29 -07:00
Ross Boucher be26ab9201 CPDictionary is now KVO compliant. 2010-05-24 10:09:39 -07:00
Thomas InghamandRoss Boucher 7519b7ab63 Added hud style for circular slider knob thing. 2010-05-24 10:09:39 -07:00
Thomas InghamandRoss Boucher aaf5c7581c Moved the non-highlighted version of the knob down one more freaking pixel. 2010-05-24 10:09:39 -07:00
Thomas InghamandRoss Boucher ce4e8dc8b7 Moved knobs down a pixel. 2010-05-24 10:09:39 -07:00
Thomas InghamandRoss Boucher 5c2e6c8ed8 Matched up the knob images to those in the file and split them into HUD as well. 2010-05-24 10:09:39 -07:00
Thomas InghamandRoss Boucher 4020f9c6c2 Adding images for sliders. 2010-05-24 10:09:38 -07:00
Thomas InghamandRoss Boucher 16bf635aca Added images that I missed because git doesn't do recursive directories. 2010-05-24 10:09:38 -07:00
Thomas InghamandRoss Boucher 99bc5a018e Added segmented control graphics and theme method to support HUD style displays for CPSegmentedControl. 2010-05-24 10:09:38 -07:00
Klaas Pieter Annema 06a553ba85 Merge branch 'master' of git://github.com/280north/cappuccino 2010-05-21 11:51:02 +02:00
klaaspieterandRandall Luecke 08b06b8632 implemented CPCoding support for CPSortDescriptor and made CPTableColumn decode it's _sortDescriptorPrototype
Conflicts:

	AppKit/CPTableColumn.j
	Tools/nib2cib/NSTableColumn.j
2010-05-20 22:51:01 -05:00
Randall Luecke 79e8b6e242 Added API for changing tableview selection color and source list gradient. 2010-05-20 19:43:01 -05:00
Klaas Pieter AnnemaandRandall Luecke 6a34329765 fixed a typo where CPThemeStateSelectedDataView was set on the header view of a table column 2010-05-20 13:42:50 -05:00
Klaas Pieter Annema f7dd6e4387 fixed a typo where CPThemeStateSelectedDataView was set on the header view of a table column 2010-05-20 18:52:43 +02:00
Klaas Pieter Annema 6a33acbb7c implemented CPCoding support for CPSortDescriptor and made CPTableColumn decode it's _sortDescriptorPrototype 2010-05-20 11:39:47 +02:00
Klaas Pieter Annema 97e4b69eaa Merge branch 'master' of git://github.com/280north/cappuccino 2010-05-20 10:50:47 +02:00
Alan RogersandRandall Luecke e96678eebc Fix for gh issue #674: passing item in userInfo for the will/did expand/collapse notifications for the OutlineView. 2010-05-20 02:12:39 -05:00
Randall Luecke 1bc8536f0e Row indexes which no longer exist are removed from selectedRowIndexes. 2010-05-19 21:15:50 -05:00
Klaas Pieter Annema 76df9be4fb implemented CPTableColumn isHidden nib2cib support 2010-05-19 18:51:18 +02:00
Klaas Pieter Annema 322d8c67b3 Fixed NSTableColumn user resizable nib2cib 2010-05-19 18:31:21 +02:00
Randall Luecke d6ac30be75 CPTableView dataViews when selected now use the new CPThemeStateSelectedDataView state to avoid conflict with other CPControl theme states. 2010-05-19 01:55:01 -05:00
Randall Luecke a9f970459b Fix for undoManager thowing exception in -canUndo. 2010-05-19 01:33:13 -05:00
Randall Luecke 76443a5d7f Fire selectionIsChanging when selecting column. closes #437 2010-05-19 01:02:39 -05:00
Randall Luecke f0501f8494 Fixed regression from last commits where children would fail to expand. 2010-05-19 00:29:12 -05:00
Blair DuncanandRandall Luecke efb752f1f4 CPOutlineView, forgot to unregister notifications prior to adding them in the last commit. 2010-05-19 00:13:26 -05:00
Randall Luecke d252e94892 CPOutlineView item Expande/Collapse delegate method notifications
Conflicts:

	AppKit/CPOutlineView.j
2010-05-19 00:13:05 -05:00
Alexander LjungbergandRandall Luecke 0be23981f3 Fixed a nonsensical CPTableview highlight style check which only accidentally did the right thing. 2010-05-18 23:57:00 -05:00
cacaodevandRandall Luecke a4cadc5fb3 CPOutlineView: fix for _retargetedDropRow not set when retargeting an item which resulted in a wrong drop line position 2010-05-18 23:56:49 -05:00
Alexander LjungbergandRandall Luecke f902223597 Edit table cells programmatically (editColumn:row:withEvent:select:). Also implements editedColumn and editedRow. 2010-05-18 23:56:42 -05:00
Alexander LjungbergandRandall Luecke 9b926be557 Support CPOutlineView inline editing. 2010-05-18 23:56:34 -05:00
Klaas Pieter Annema db568af302 made sure CPViewController calls viewDidLoad if it's view property is set directly 2010-05-17 12:44:11 +02:00
Klaas Pieter Annema e7cf20a723 Merge branch 'master' of git://github.com/280north/cappuccino 2010-05-17 11:19:14 +02:00
Randall Luecke 202243f711 fixed typo in CPViewAnimation. 2010-05-16 13:41:09 -05:00
Randall Luecke c5f51ae826 Merge branch 'master' of git://github.com/280north/cappuccino 2010-05-16 13:26:45 -05:00
Randall Luecke 61b9c7a1ee Moved depreciated CPGeometry methods to CGGeomotry and fixed the filename in the header. 2010-05-16 13:19:28 -05:00
Saikat ChakrabartiandRoss Boucher 4520715b5b Making CPURLConnection authentication challenges happen before the delegate gets a response 2010-05-15 19:14:57 -07:00
Thomas InghamandRoss Boucher 6ef829e9ec Added documentation in the form of source code comments; verified using doxygen and the included recipe file. 2010-05-15 12:36:36 -07:00
Alexander LjungbergandRoss Boucher 791e65c88b Improved CPArray sortUsingDescriptors performance by about 3% by pulling the descriptor count out of the sort function. 2010-05-15 12:32:19 -07:00
Ross Boucher fddcde757f Add a more specific cache header.
Closes #649.
2010-05-15 12:22:29 -07:00
Paul BaumgartandRoss Boucher 66180f8de4 change @property to @accessors in pre-processor error messages 2010-05-15 12:19:35 -07:00
Paul BaumgartandRoss Boucher bc5a21d545 Change objj_exception_throw to manually throw an exception, because objj_exception_throw doesn't exist anymore. 2010-05-15 12:19:06 -07:00
Paul BaumgartandRoss Boucher fc8525e4d8 throw a regular Error() exception in Runtime.js because objj_exception doesn't exist anymore 2010-05-15 12:19:00 -07:00
Francisco Ryan Tolmasky I 8dd61155bf Merge branch 'master' of github.com:280north/cappuccino 2010-05-12 19:23:06 -07:00
Francisco Ryan Tolmasky I 5a89dfe8f4 Fix for identifying when we can use platform windows.
Reviewed by me.
2010-05-12 19:22:31 -07:00
Ross Boucher 80b70ec6b9 Can't sprited resources whos resulting dataURL is larger than 32k, not resources which themselves are over 32k. 2010-05-12 19:08:30 -07:00
Francisco Ryan Tolmasky I ac81ab458c Fix for same html appearing multiple times in CPWebView when using loadHTMLString: many times in succession.
Reviewed by me.
2010-05-12 18:41:14 -07:00
Ross Boucher 23b76874df A few IE fixes for web view. 2010-05-12 18:23:33 -07:00
Randall Luecke bc54fcf6c0 Merge branch 'master' of git://github.com/280north/cappuccino 2010-05-12 19:46:34 -05:00
Randall Luecke e0a3a683a5 access ivars directly from within CPTableHeaderView class. 2010-05-12 19:44:07 -05:00
Randall Luecke c31786c4c1 Refactored autoresizing 2010-05-12 19:01:28 -05:00
Ross Boucher 13a5c7f215 indexOf is not a safe operation on arrays. 2010-05-12 16:51:28 -07:00
Klaas Pieter AnnemaandRoss Boucher ee2f361425 Reimplemented setImageDimsWhenDisabled: on CPButton to only dim the image instead of the entire button 2010-05-12 16:51:28 -07:00
Scott KyleandRoss Boucher 9eab2071dc In CPImageView, performDragOperation: should return a BOOL 2010-05-12 16:51:28 -07:00
Randall Luecke 61d7fe04e8 If we tell the tableview not to draw a selection then we shouldn't draw it... 2010-05-12 18:43:56 -05:00
Randall Luecke d3161422db Updated TableTest adding a checkbox as a dataview for a column. 2010-05-12 17:14:25 -05:00
Ross Boucher d1ae1bd41f Menu window's should open in the same platform window as the view they are attached to. 2010-05-12 10:36:48 -07:00
Francisco Ryan Tolmasky I 6384bed9cc Properly handle window.location= links as well.
Reviewed by me.
2010-05-12 09:45:58 -07:00
Francisco Ryan Tolmasky I be75e4948d Merge branch 'master' of github.com:280north/cappuccino 2010-05-12 08:54:15 -07:00
Francisco Ryan Tolmasky I 337f5d9e73 Correctly handle targeted links in NativeHost.
Reviewed by me.
2010-05-12 08:53:50 -07:00
Ross Boucher 4afa2bfada clean up style issues 2010-05-11 23:20:02 -07:00
Randall Luecke b94174f9e1 Updated TableTest to provide a test case for tables that do not sit at (0,0) of a window. 2010-05-11 19:43:01 -05:00
Randall Luecke bf71045381 Fixed bug where column reordering would be off if the table didn't sit at (0,0) on a window. 2010-05-11 19:39:51 -05:00
Francisco Ryan Tolmasky I 0ade0e1361 Merge branch 'master' of github.com:280north/cappuccino 2010-05-11 14:05:51 -07:00
Ross Boucher 0f02e0d8dd Revert "added enumerateWithBlock: to CPArray"
This reverts commit 39bb8e3418.
2010-05-11 12:40:37 -07:00
klaaspieterandRandall Luecke 7c786407a5 Merge remote branch 'klaaspieter/column-reordering'
Conflicts:
	AppKit/CPTableHeaderView.j
2010-05-11 01:18:56 -05:00
Klaas Pieter AnnemaandRandall Luecke 79ba8fecd5 made column reordering work with scrolled content 2010-05-11 00:25:54 -05:00
Klaas Pieter AnnemaandRandall Luecke 213c81ed4d made table column reordering work in non full-bridged apps 2010-05-11 00:25:47 -05:00
Klaas Pieter AnnemaandRandall Luecke d7432c376d fixed a bug where column reordering would break when the last column was hidden 2010-05-11 00:25:39 -05:00
Klaas Pieter AnnemaandRandall Luecke b8c7d6ea86 some cleanup 2010-05-11 00:25:30 -05:00
Randall Luecke 983f0a92b2 - fixed a out of bounds error when clicking in the table header outside of any column
- made the dragged table column appear gray
- gave the tablecolumn drag view a white background

Conflicts:

	AppKit/CPTableView.j
2010-05-11 00:25:19 -05:00
Klaas Pieter AnnemaandRandall Luecke 256cc902eb - switch columns when the dragged column is more than halfway over the previous/next column
- constrain the horizontal coordinates within the header view
2010-05-11 00:24:16 -05:00
Klaas Pieter AnnemaandRandall Luecke f7b766cc4a - made the _dragViewForTableColumn:event:offset: method private
- removed the multiple column support from _dragViewForTableColumn:event:offset: (Cocoa doesn't allow multiple column selection / dragging)
- made the dragview the size of the dragged column
2010-05-11 00:24:03 -05:00
Klaas Pieter AnnemaandRandall Luecke dca66f300d - gave the drag column a proper 'image' representation
- constrained the drags y coordinates
- made sure a drag is never out of bounds
2010-05-11 00:23:55 -05:00
Klaas Pieter AnnemaandRandall Luecke fd9dac8122 - refactored mouse interaction
- implemented basic column reordering
2010-05-11 00:23:40 -05:00
Klaas Pieter AnnemaandRandall Luecke 8b168e76af refactored CPTableHeaderView mouse interaction 2010-05-11 00:18:21 -05:00
Randall Luecke 5b518797d7 fixed CPTableView moveColumn:
Conflicts:

	AppKit/CPTableView.j
2010-05-11 00:18:05 -05:00
Randall Luecke e5275514dd OutlineView items auto expand when hovering over them. 2010-05-11 00:05:12 -05:00
cacaodevandRandall Luecke 0d35b38282 CPOutlineView: Fix a bug where newly expanded items would have a white disclosure control.
In CPTableView, add a method for data view selection. Use it in CPOutlineView for disclosure selection and do not subclass the entire -selectRows:... method.
               Darken disclosure control when pressed depending on the selected state.
2010-05-10 15:03:06 -05:00
Randall Luecke 837dcbf19d Merge branch 'master' of git://github.com/280north/cappuccino 2010-05-10 15:02:19 -05:00
Ross BoucherandRandall Luecke e68d70cf1d Make mouse wheel events work in CPWebView in Firefox 3+ 2010-05-09 21:46:02 -05:00
Klaas Pieter Annema 1171e2c9af Merge branch 'master' of git://github.com/280north/cappuccino
Conflicts:
	Foundation/CPKeyValueObserving.j
2010-05-07 10:23:27 +02:00
Klaas Pieter Annema e5873caf04 fixed a typo in objectValueForTableColumn:row: 2010-05-07 09:38:23 +02:00
Ross Boucher 34ee33aea0 Merge commit '6f0ca9d94c217bc5e3c3' into bindings 2010-05-06 13:35:00 -07:00
Klaas Pieter AnnemaandRoss Boucher 2d93d12cad Made bindings branch jake buildable 2010-05-06 13:33:38 -07:00
Ross Boucher c43b80cb91 Make mouse wheel events work in CPWebView in Firefox 3+ 2010-05-06 12:41:01 -07:00
Ross Boucher 542e491bb4 whitespace cleanup. 2010-05-06 11:26:56 -07:00
Klaas Pieter AnnemaandRoss Boucher 9c9eb519df call willChange* and didChange* methods on the actual classes 2010-05-06 11:23:49 -07:00
Klaas Pieter Annema 0a96cb8eb3 call willChange* and didChange* methods on the actual classes 2010-05-06 17:36:11 +02:00
Ross Boucher 90975c96f9 Updates for scrolling behavior in webview. 2010-05-05 14:05:09 -07:00
Klaas Pieter Annema 2fd85ab78f made column reordering work with scrolled content 2010-05-05 14:08:06 +02:00
Klaas Pieter Annema a0cf7d5787 made table column reordering work in non full-bridged apps 2010-05-05 12:56:23 +02:00
Klaas Pieter Annema e7fc9d9912 fixed a bug where column reordering would break when the last column was hidden 2010-05-05 12:25:09 +02:00
Klaas Pieter Annema bdb0fb1310 some cleanup 2010-05-05 12:24:05 +02:00
Klaas Pieter Annema 006f7e0c15 - fixed a out of bounds error when clicking in the table header outside of any column
- made the dragged table column appear gray
- gave the tablecolumn drag view a white background
2010-05-05 12:23:55 +02:00
Klaas Pieter Annema 93afa11ef9 - switch columns when the dragged column is more than halfway over the previous/next column
- constrain the horizontal coordinates within the header view
2010-05-05 12:23:07 +02:00
Klaas Pieter Annema 040e7bc9ee - made the _dragViewForTableColumn:event:offset: method private
- removed the multiple column support from _dragViewForTableColumn:event:offset: (Cocoa doesn't allow multiple column selection / dragging)
- made the dragview the size of the dragged column
2010-05-05 12:23:00 +02:00
Klaas Pieter Annema 6bb8514253 - gave the drag column a proper 'image' representation
- constrained the drags y coordinates
- made sure a drag is never out of bounds
2010-05-05 12:22:53 +02:00
Klaas Pieter Annema 85283cff38 - refactored mouse interaction
- implemented basic column reordering
2010-05-05 12:22:42 +02:00
Klaas Pieter Annema ef68408fff refactored CPTableHeaderView mouse interaction 2010-05-05 12:22:36 +02:00
Klaas Pieter Annema 71104e4902 fixed CPTableView moveColumn: 2010-05-05 12:22:16 +02:00
Klaas Pieter Annema 65362e727a Merge branch 'master' of git://github.com/280north/cappuccino 2010-05-05 12:03:51 +02:00
Ross Boucher 5044ce4236 Add a doctype when creating new platform windows. 2010-05-04 22:55:06 -07:00
Francisco Ryan Tolmasky I b4aca3410f Merge branch 'master' of github.com:280north/cappuccino 2010-05-04 22:08:08 -07:00
Ross Boucher b5971eae95 Missed this, it's no longer needed. 2010-05-04 19:09:06 -07:00
Tom Robinson 4b775796be Add a test for capp gen, press, and flatten. 2010-05-04 15:41:50 -07:00
Tom Robinson e97af776a0 Fix press/flatten due to changes to CFHTTPRequest. 2010-05-04 15:40:35 -07:00
Ross Boucher e83e5b7c29 Only send open if we aren't already open 2010-05-04 15:04:51 -07:00
Francisco Ryan Tolmasky I 179ef85f4e Final timer fix.
Reviewed by me.
2010-05-04 14:49:31 -07:00
Ross Boucher 5b4603b6a7 add missing ivar declaration to CPPlatformWindow 2010-05-04 13:53:56 -07:00
Francisco Ryan Tolmasky I fc2560eb32 Fix for native drag and drop breaking across different window starts.
Reviewed by me.
2010-05-04 10:28:51 -07:00
Francisco Ryan Tolmasky I 2c23c0ffa7 Disable new timer stuff for CommonJS.
Reviewed by me.
2010-05-04 10:09:16 -07:00
Klaas Pieter Annema fda974458e Merge branch 'master' of git://github.com/280north/cappuccino 2010-05-04 15:55:17 +02:00
Francisco Ryan Tolmasky I efe4d5f339 Merge branch 'master' of github.com:280north/cappuccino 2010-05-04 03:32:51 -07:00
Francisco Ryan Tolmasky I 032fe7cc0c Fix for timers not working if they are created outside of a run loop.
Reviewed by me.
2010-05-04 03:32:16 -07:00
Randall Luecke 50c519ec69 Fixed issue with CPWebView where document.body didn't exist when reloaded quickly. 2010-05-03 17:34:12 -04:00
Tom Robinson af566ec08a Fix LoadTimeTest, location.host includes the port. 2010-05-03 00:25:35 -07:00
Ross Boucher cb7879eecf Make CFHTTPRequests re-fireable. 2010-05-02 12:58:36 -07:00
Ross Boucher b1825334dd If the vertical status changes, or the pane splitter status changes, we need to update the image value. 2010-05-01 20:40:38 -07:00
Ross Boucher 09727909b3 Fix for menuless windows. Closes #640. 2010-05-01 14:47:43 -07:00
Ross Boucher f98d3bd44b Add global 403 handler for CFHTTPRequest, to make it easier to catch authentication challenges. 2010-05-01 11:57:32 -07:00
Ross Boucher 1545f7b60a Return the cib created in CibLoading.j methods. 2010-04-29 15:38:33 -07:00
Ross Boucher 2453e403ef Make nil a completely valid object in a CPArray.
Closes #630.
2010-04-29 12:04:44 -07:00
Klaas Pieter Annema 2bb16c3617 Merge branch 'master' of git://github.com/280north/cappuccino 2010-04-29 14:28:16 +02:00
Klaas Pieter Annema 4ef9202e92 made the tableview handle hiding and showing of columns properly 2010-04-29 14:22:46 +02:00
Tom Robinson 22668b6b43 Use 127.0.0.1 instead of localhost in case localhost != loopback. 2010-04-28 02:23:07 -07:00
Francisco Ryan Tolmasky I f9c786f3eb Merge branch 'master' of git@github.com:280north/cappuccino 2010-04-28 02:06:48 -07:00
Francisco Ryan Tolmasky I 0f2ee1966e Only create main menu in code if no cib is loaded.
Reviewed by me.
2010-04-28 02:06:01 -07:00
Tom Robinson 62e520a6a5 Some more NativeHost building enhancements. 2010-04-28 01:45:04 -07:00
Ross Boucher 2f9cf6bc9b Add action buttons to button bars. 2010-04-27 22:11:17 -07:00
Ross Boucher e03cfe8287 Missing printResults() in Jakefile for ThemeDescriptor template
Conflicts:

	Tools/capp/Resources/Templates/ThemeDescriptor/Jakefile
2010-04-27 13:16:17 -07:00
Tom Robinson 0d97dfacd6 give zero sized borderless bridge windows a default size if we're not in the browser so they show up in NativeHost. 2010-04-27 12:56:24 -07:00
Francisco Ryan Tolmasky I 6ac0191451 Show main menu in cibless apps.
Remaining: Make a main menu with quit for desktop version, without for web version.

Reviewed by me.
2010-04-27 11:33:00 -07:00
Ross Boucher f5b360f66c Move a lot of common initialization code into the _init method. 2010-04-27 10:49:50 -07:00
Ross Boucher 1d5c21fa72 If we decode a scroll view without a header clip view, create one. 2010-04-27 10:49:50 -07:00
Klaas Pieter Annema 015aca9165 Merge branch 'master' of git://github.com/280north/cappuccino 2010-04-27 10:36:12 +02:00
Francisco Ryan Tolmasky I d3e1c39e35 Merge branch 'master' of git@github.com:280north/cappuccino 2010-04-27 01:05:14 -07:00
Francisco Ryan Tolmasky I ae47509aa7 Add convinience methods for dealing with multiple objects and controls.
Reviewed by me.
2010-04-27 01:04:46 -07:00
Tom Robinson 5ff798306f Copy CFBundleIconFile in NativeHost building. 2010-04-26 23:19:05 -07:00
Ross Boucher c41ffc14c7 checkboxes and radio buttons shouldn't be bold. 2010-04-26 21:36:45 -07:00
Ross Boucher 1e7a3bef0d Fix a potential infinite loop in CPBrowser. 2010-04-26 12:56:52 -07:00
Nicholas Small 243f564396 Fix typo in new autoscroll stuff. 2010-04-26 11:11:42 -04:00
Tom Robinson dae1e44a8f Merge Cappuccino Info.plist into NativeHost's Info.plist. 2010-04-25 23:22:16 -07:00
Tom Robinson 67bcc29baf NativeHost. 2010-04-25 22:33:31 -07:00
Ross Boucher cdb089778c autoscroll when drag selecting. 2010-04-25 15:43:23 -07:00
Ross Boucher 5e43a02ffa Fix some faulty validation logic. 2010-04-25 15:43:22 -07:00
Ross Boucher 7395d13c3e Typo in CPJSONPConnection. 2010-04-25 15:43:22 -07:00
Tom Robinson f6000468db Missing printResults function in ThemeDescriptor Jakefile. 2010-04-25 14:58:27 -07:00
Stephen IerodiaconouandRoss Boucher 09e52d82bf Code style clean up, as per style guide 2010-04-24 15:06:12 -07:00
Ross Boucher 0e98f44a93 Fix for IE transparent backgrounds not being resized.
Closes #604.
2010-04-24 14:51:10 -07:00
Ross Boucher 6d595c1344 Collection view should tile itself to be the height of its superview if inside a clip view. 2010-04-24 11:10:58 -07:00
Ross Boucher 5f6f997095 Only attempt to scroll views, not windows. 2010-04-24 11:10:36 -07:00
Ross Boucher 6662fabcb8 Tests for the bug exposed in the previous cparray commit. 2010-04-23 16:43:22 -07:00
Stephen IerodiaconouandRoss Boucher 7577cf8645 Fix error in initWithArray:copyItems: 2010-04-23 16:42:55 -07:00
Ross Boucher 8340791824 Don't let color wells work if they are disabled.
Closes #626.
2010-04-23 16:34:47 -07:00
Ross Boucher 14f0d16fae Update scrollWheel: to propagate unused scroll deltas to parent scroll views. 2010-04-23 16:16:46 -07:00
cacaodevandRoss Boucher e1ad4a2fce CPTableView: remove custom scrolling now that it's handled in the CPDragServer + CPClipView 2010-04-23 14:31:25 -07:00
Ross Boucher f67580e2b2 Add support for automatically scrolling during drag and drop operations. 2010-04-23 14:00:47 -07:00
Ross Boucher 31f408478a Update to scrolling behavior. 2010-04-23 12:03:25 -07:00
Klaas Pieter Annema fd93b6e5f7 Merge branch 'master' of git://github.com/280north/cappuccino 2010-04-23 16:34:59 +02:00
Klaas Pieter Annema 39bb8e3418 added enumerateWithBlock: to CPArray 2010-04-23 16:34:40 +02:00
Randall Luecke ab6d5d6a90 Added connectionDidFinsihLoading delegate to CPJSONPConnection 2010-04-23 01:29:46 -04:00
Ross Boucher 6b3600d67b Slight update to button bar theme values. 2010-04-22 11:50:06 -07:00
Francisco Ryan Tolmasky I bf8ff44b84 Merge branch 'master' of git@github.com:280north/cappuccino 2010-04-21 22:56:21 -07:00
Francisco Ryan Tolmasky I 72a3888062 Add ObjectiveJ global to CommonJS so that references to it aren't broken in Cappuccino.
Reviewed by me.
2010-04-21 22:55:46 -07:00
Ross Boucher 4479233bea Return nil fonts if they are the aristo default, so that the theme default is used instead of the arist default (for custom themes). 2010-04-21 20:57:53 -07:00
Alexander LjungbergandRoss Boucher a7021e6b66 Fixed a parameter type typo. 2010-04-21 15:48:47 -07:00
Alexander LjungbergandRoss Boucher 0f5dd9d469 [CPSet description] with unit test. 2010-04-21 15:48:39 -07:00
Alexander LjungbergandRoss Boucher 388f008189 Fixed: CPCollectionView frameForItemsAtIndexes used the deprecated method rectForItemAtIndex causing warnings. 2010-04-21 15:47:48 -07:00
Alexander LjungbergandRoss Boucher 639a32ea7e CPWindow alpha value support. 2010-04-21 15:47:25 -07:00
Alexander LjungbergandRoss Boucher 5838f1aec8 Implemented CPCoding for CPNull. 2010-04-21 15:36:29 -07:00
Ross Boucher d2399b6157 Add support for not clipping to bounds in cpview. 2010-04-21 14:15:05 -07:00
Ross Boucher b1282b4362 Fix an infinite recursion bug in CPBrowser, and add support for looking up a column/row by location. 2010-04-21 12:58:31 -07:00
Francisco Ryan Tolmasky I bbd402fcff Partial fix for HTML5 drag and drop with collection views.
Reviewed by me.
2010-04-20 23:51:18 -07:00
Klaas Pieter Annema 6f0ca9d94c Merge branch 'master' into bindings
Conflicts:
	AppKit/CPTableView.j
	AppKit/_CPCornerView.j
	Foundation/CPArray.j
	Foundation/CPKeyValueCoding.j
	Foundation/CPKeyValueObserving.j
2010-04-15 10:57:46 +02:00
Tom Robinson a18fb1b686 Add manifest generation options to press and flatten, since manifests need to be updated after each is run. 2010-04-12 13:47:38 -07:00
Francisco Ryan Tolmasky I 6a72e1b6ff Merge branch 'master' of git@github.com:280north/cappuccino 2010-04-12 12:22:25 -07:00
Francisco Ryan Tolmasky I b3141f1a62 Add CPApplicationWillTerminateNotification.
Reviewed by me.
2010-04-12 12:21:45 -07:00
Randall Luecke aea8f1f0dc Added proper background color to the tableview. 2010-04-12 02:09:46 -04:00
Francisco Ryan Tolmasky I 8aecf880e5 Merge branch 'master' of git@github.com:280north/cappuccino 2010-04-09 22:22:55 -07:00
Francisco Ryan Tolmasky I 7d5ce51910 Upped the version number to 0.8.1.
Reviewed by me.
2010-04-09 22:22:35 -07:00
Ross Boucher cfc8ccafce Remove typo. 2010-04-09 14:56:54 -07:00
Kelly McDonaldandRoss Boucher e11dfc2875 CPDragServer was checking the selector on the delegate of draggedImage:endAt:operation: but calling draggedImage:endedAt:operation:. I changed so that it uses endedAt to better reflect what is done in cocoa 2010-04-09 14:56:43 -07:00
Ross Boucher b3ef31ad05 Fixed: [CPArray isEqualToArray:nil] threw an exception instead of returning NO.
Conflicts:

	Foundation/CPArray.j
	Tests/Foundation/CPArrayTest.j
2010-04-09 14:51:46 -07:00
Ross Boucher 70410d6311 Fix the buttonNumber method of CPEvent.
Closes #70.
2010-04-09 14:38:08 -07:00
Ross Boucher 4cc7dec35b Throw syntax error for # followed by anything other than pragma. 2010-04-09 14:34:02 -07:00
Ross Boucher 47ecd40c4f Made the pre-processor capable of recognizing and ignoring Xcode's '#pragma mark' mark-ups
Conflicts:

	Objective-J/Preprocessor.js
2010-04-09 14:26:29 -07:00
saikatandRoss Boucher 489f2bcfa0 Reverting 1c9763eaa8 - autoresizing the contentview breaks sizetofit 2010-04-09 14:18:20 -07:00
Ross Boucher 16590e0603 Closes #590.
Closes #594.
2010-04-09 14:17:11 -07:00
Paul BaumgartandRoss Boucher f50cda9abc change CPAccordionItem to CPAccordionViewItem in CPAccordionView
selector types. Closes gh-596.
2010-04-09 13:58:05 -07:00
Francisco Ryan Tolmasky I 7543968203 Merge branch 'master' of git@github.com:280north/cappuccino 2010-04-08 23:59:00 -07:00
Francisco Ryan Tolmasky I 54685b1f36 One additional fix for IE not loading in certain occasions.
Reviewed by me.
2010-04-08 23:58:47 -07:00
Francisco Ryan Tolmasky I abdc601d92 Fix for IE not loading bug.
Reviewed by me.
2010-04-08 23:58:31 -07:00
Tom Robinson 9f50f08065 Add automated HTML5 cache manifest generation. Disabled by default. 2010-04-07 22:46:23 -07:00
Tom Robinson aabb1fa6f2 Move CPCursor test out of Resources. 2010-04-07 16:03:42 -07:00
Tom Robinson 4b770714bd Update starter task to include version of bootstrap which installs Cappuccino packages. 2010-04-06 12:54:23 -07:00
Ross Boucher 8175dbca53 Updates to the Jakefile and capp gen. 2010-04-06 12:26:35 -07:00
Tom Robinson c91332afb4 Add the other MobileSafari meta/link tags. 2010-04-05 20:09:04 -07:00
Tom Robinson 08fb1b33b4 Add viewport tag to templates. Fixes drawing errors on MobileSafari. 2010-04-05 18:14:04 -07:00
Ross Boucher cd6b6afc65 Don't convert text fields to bold default system font. 2010-04-05 10:38:20 -07:00
Tom Robinson cd4a70ea78 Add hook to CPApplicationMain to notify parent frame (if app is in a child frame of same origin) 2010-04-04 18:39:47 -07:00
Tom Robinson eb24ba9835 Re-enable flatten compression by default. 2010-04-01 23:48:48 -07:00
Tom Robinson 468869821f Add charset attributes to all external script tags, including flatten. Fixes unicode bugs in flatten. 2010-04-01 23:41:08 -07:00
Tom Robinson 0c85dbf9b0 Add some charset options, and disable compressor by default. 2010-04-01 23:15:47 -07:00
Tom Robinson 2db47e413e Add comrpessor support to flatten. 2010-04-01 12:01:16 -07:00
Tom Robinson b8fddc98bf Fixes flatten, splitting mode. Also escape dollar signs before replacing. 2010-04-01 11:12:08 -07:00
Tom Robinson 467f798147 Fixes flatten, non-splitting mode. 2010-04-01 11:11:58 -07:00
Ross Boucher 374f3d13f1 Convert default IB fonts to default Cappuccino fonts 2010-03-31 21:31:09 -07:00
Tom Robinson b0a35a183f Only enable debug logger in browsers, not command line utilities. 2010-03-31 17:28:46 -07:00
Francisco Ryan Tolmasky I 74e349ed33 Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-31 17:05:32 -07:00
Francisco Ryan Tolmasky I c57aa2ac5e Fix for menu bar being broken if displayed after a window is ordered front in IE.
Reviewed by me.
2010-03-31 17:04:35 -07:00
Ross Boucher acac29dcda Merge branch 'master' of github.com:280north/cappuccino 2010-03-31 16:37:16 -07:00
Paul BaumgartandTom Robinson 675969af6d Add some dependency checking to bootstrap.sh: make sure correct JVM is
being used and ensure other dependencies are installed and on the $PATH.
2010-03-31 15:00:09 -07:00
Tom Robinson ce32177e1d Use "CommonJS" task as the dependency for "test" task for now. 2010-03-31 13:53:09 -07:00
Randall Luecke e956d61a08 Fixed bug introduced by renaming of private class. 2010-03-31 16:41:13 -04:00
Alexander LjungbergandRoss Boucher 068cdb9817 CPNull valueForKey:X returns CPNull for any value of X, paralleling [nil valueForKey:X]. Verified against Cocoa through empirical testing. 2010-03-31 13:17:42 -07:00
Randall Luecke 0ec7d4cd9a Made drag feedback view in the tableview more correct, fixed encoding issues.
Conflicts:

	AppKit/CPTableView.j
2010-03-31 16:11:10 -04:00
Nicholas Small 6a8126337c Added right click responder methods and context menu support. 2010-03-31 15:56:18 -04:00
Ross Boucher 12db25a829 Fix for a potential error in IE when setting a width to a negative value. 2010-03-31 12:11:21 -07:00
Ross Boucher a347bfb8b1 Sprite images recursively. 2010-03-31 11:10:17 -07:00
Francisco Ryan Tolmasky I 9255af210c Fix for loading Cappuccino apps locally on Windows.
Reviewed by me.
2010-03-30 16:28:42 -07:00
Tom Robinson 0b3264a99d Enable default logger in debug frameworks. Add configurable options to index-debug.html. 2010-03-30 14:12:59 -07:00
Ross Boucher 2bf16da441 These menu key equivs were incorrect. 2010-03-30 11:10:36 -07:00
Ross Boucher 5c4d890100 Fix a nil variable error that caused problems in Firefox 2. 2010-03-30 10:52:48 -07:00
Francisco Ryan Tolmasky I 99282026fa One more fix for image spriting.
Reviewed by me.
2010-03-30 00:45:11 -07:00
Francisco Ryan Tolmasky I 8f4b2a7cfd Fail more gracefully when main cib is not found.
Reviewed by me.
2010-03-29 23:20:31 -07:00
Randall Luecke c78feda3d6 Fixed nib2cib bug with cornerview where resources were not loaded from the correct location. 2010-03-30 01:45:36 -04:00
Francisco Ryan Tolmasky I a279d62c88 Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-28 11:40:38 -07:00
Francisco Ryan Tolmasky I 8d1f787179 Fix for a few minor regressions:
1. Split out flatten specific code to get file size back down.
2. Fix for non-native string URL not working with the URLCache (typeof x !=== "string")
3. Fix for slight IE performance regression.

Reviewed by me.
2010-03-28 11:39:36 -07:00
Ross Boucher 7ab41cf195 If there is no key window or no main window make the first opened window those things. 2010-03-28 09:03:33 -07:00
Ross Boucher df728b7a21 Support terminating method signatures with ;. Closes #416. 2010-03-28 08:51:35 -07:00
Francisco Ryan Tolmasky I cba26faf9b Fix for HelloWorld not flattening correctly.
Reviewed by me.
2010-03-27 19:31:16 -07:00
Francisco Ryan Tolmasky I c4c1cffc01 Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-27 18:53:03 -07:00
Francisco Ryan Tolmasky I 321706e5c6 Fix for user code errors during load not being reported (Cappuccino failing silently).
Reviewed by me.
2010-03-27 18:52:19 -07:00
Ross Boucher 47bf4c0baa Finish split view cursor implementation.
Closes #494.
2010-03-27 15:47:10 -07:00
Alexander LjungbergandRoss Boucher fc628c1221 CPSplitView resize cursors now require [[self window] setAcceptsMouseMovedEvents:YES]; to be called manually pending a CPTrackingArea based implementation. 2010-03-27 15:47:10 -07:00
Ross Boucher eb6a03704a Proper resize cursors for CPSplitView. Also enables resize cursor for additionalEffectiveRectOfDividerAtIndex areas.
Conflicts:

	AppKit/CPSplitView.j
2010-03-27 15:47:10 -07:00
Francisco Ryan Tolmasky I 7b855e6c68 Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-27 13:56:35 -07:00
Francisco Ryan Tolmasky I fe0818c612 Don't generate image files if there aren't any.
Reviewed by me.
2010-03-27 13:54:07 -07:00
Ross Boucher 74dabcae8a Update the CPDictionary test suite. 2010-03-27 13:52:44 -07:00
Emmanuel MaillardandRoss Boucher daf7870bab - add containsKey: method 2010-03-27 13:41:32 -07:00
Ross Boucher 64da7f8775 define out DOM code from _CPImageAndTextView.
Closes #562.
2010-03-27 13:37:13 -07:00
aburkhalterandRoss Boucher 6cfa11a94d Initial boilerplate and file for putting the untested (at least not directly) CPView.j under test. Initial test to confirm we can actually create the object and a test demonstrating issue #562. 2010-03-27 13:33:04 -07:00
Ross Boucher db3c6c1463 A few minor updates to the pathExtension patch. 2010-03-27 13:25:44 -07:00
Emmanuel MaillardandRoss Boucher 65a669a9a1 - correct pathExtension and stringByDeletingPathExtension 2010-03-27 13:23:55 -07:00
Emmanuel MaillardandRoss Boucher 33f56bb203 - implement stringByDeletingPathExtension 2010-03-27 13:23:32 -07:00
Emmanuel MaillardandRoss Boucher 1ff873e170 - add tests for pathExtension and stringByDeletingPathExtension 2010-03-27 13:22:36 -07:00
Ross Boucher b0e0156880 Fix support for initial first responder. 2010-03-27 13:08:47 -07:00
Ross Boucher 896f36dffb A better (but not perfect) way to handle the browser's first responder state. 2010-03-27 11:27:44 -07:00
Ross Boucher eae975652e Add default line break mode. 2010-03-26 16:59:02 -07:00
Ross Boucher e46d1a793c autoresize the cpbrowser test browser. 2010-03-26 16:41:33 -07:00
Ross Boucher 1c9763eaa8 CPBox should autoresize its content view. 2010-03-26 16:41:23 -07:00
Ross Boucher 686370ac0e Add convenience accessors for the browser's selected items. 2010-03-26 15:52:53 -07:00
Ross Boucher e4ca057e4c Fix import directives. 2010-03-26 14:27:46 -07:00
Ross Boucher ac5a0e3dfc Add CPBrowser manual test app. 2010-03-26 14:00:51 -07:00
Ross Boucher a580b522e3 Add initial CPBrowser implementation. 2010-03-26 14:00:30 -07:00
Ross Boucher af53c271c7 Fix a few naming convention violations.
Make dragView.... use the columns its passed, rather than computing from scratch.
2010-03-26 13:59:41 -07:00
Ross Boucher 4476dad395 Whitespace fix. 2010-03-26 10:36:08 -07:00
Emmanuel MaillardandRoss Boucher b7b2dd2915 - CGPathAddQuadCurveToPoint fix for an unknown variable when using a transformation matrix 2010-03-26 10:36:08 -07:00
Francisco Ryan Tolmasky I efb6a0f5c6 Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-26 01:31:39 -07:00
Francisco Ryan Tolmasky I deba653661 Fix for unrecognized selector in CPURL's initWithCoder:.
Reviewed by me.
2010-03-26 01:30:50 -07:00
Ross Boucher eb831dc4ac Typo. Closes #572. 2010-03-25 10:40:37 -07:00
Scott KyleandRoss Boucher b0d355a71c Some somewhat minor style fixes 2010-03-24 19:46:38 -07:00
Ross Boucher af11b4e423 Fix for pattern images not being displayed correctly under the new background color system 2010-03-23 14:32:24 -07:00
Ross Boucher 0cf86318ce Make semi-transparent background colors work in browsers that don't support RGBA.
Closes #569.
2010-03-23 14:26:32 -07:00
Ross Boucher 4175b762c3 Disable new syntax check while we work out the build issue some people are having. 2010-03-23 13:29:55 -07:00
Ross Boucher 3ddcb5f118 Remove duplicate method declaration. 2010-03-23 13:29:43 -07:00
Ross Boucher d0ad865976 Add the with{} back in for Class methods, instead take the disallowed list from objj_class. 2010-03-23 11:21:59 -07:00
Ross Boucher 7013b34897 Add a few additional syntax checks.
Throw an error if a method uses a parameter name that is also an ivar name.
Stop using with{} block for class methods.
2010-03-23 11:21:59 -07:00
Ross Boucher bbbae36e6a Missing - on a method. 2010-03-23 11:21:59 -07:00
Francisco Ryan Tolmasky I 34c3a9530b Fixed a bug where CPKeyedUnarchiver would incorrectly unarchive 0 as null.
Reviewed by me.
2010-03-23 02:06:44 -07:00
Francisco Ryan Tolmasky I 78cb522874 Temporarily revert "Make semi-transparent background colors work in browsers that don't support RGBA."
This fix was making lots of resources not show up.

This reverts commit f8c13f1e30.
2010-03-23 01:22:59 -07:00
Francisco Ryan Tolmasky I e8a0d2acf6 Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-23 00:04:59 -07:00
Ross Boucher f8c13f1e30 Make semi-transparent background colors work in browsers that don't support RGBA.
Closes #569.
2010-03-22 19:00:49 -07:00
Randall Luecke 4b272a76fd Merge branch 'master' of git://github.com/280north/cappuccino 2010-03-22 19:27:13 -04:00
Randall Luecke f73d96af08 Fixed black background of dragview in Opera and IE. 2010-03-22 19:24:32 -04:00
Scott KyleandRoss Boucher bb0835e2f3 CPImageView should send action on drop, as in Cocoa 2010-03-22 16:15:02 -07:00
Ross Boucher ef4c108b9e Date test wasn't accurately accounting for daylight savings time. 2010-03-22 15:08:29 -07:00
Ross Boucher 319b9ed00f Use === not ==. 2010-03-22 14:53:49 -07:00
Alan RogersandRoss Boucher 35b62ca53f Updated test and fix for gh issue #539 2010-03-22 14:53:07 -07:00
Alan RogersandRoss Boucher 4e1e6f3c0b Little fix for CPDictionary, we should not try and recursively convert null JSON objects. 2010-03-22 14:52:55 -07:00
Alan RogersandRoss Boucher c8f3445fa6 Adding a unit test to verify fix to +[CPDictionary dictionaryWithJSObject:(JSObject)object recursively:(BOOL)recursively] 2010-03-22 14:52:49 -07:00
Emmanuel MaillardandRoss Boucher 7aa1ae6bd4 - fix typo 2010-03-22 14:43:53 -07:00
Emmanuel MaillardandRoss Boucher 58179939bb - fix a typo in documentation 2010-03-22 14:43:31 -07:00
Scott KyleandRoss Boucher 5d3eae9022 deleteBackwards: => deleteBackward: 2010-03-22 14:30:48 -07:00
aburkhalterandRoss Boucher 05f8a10b3d Trivial syntax fixes. 2010-03-22 14:29:27 -07:00
Francisco Ryan Tolmasky I 6843df410a Fix for empty data URLs, MHTML, etc. files being created when no image resources exist, causing a useless xhr.
Reviewed by me.
2010-03-21 14:30:31 -07:00
Randall Luecke f324577014 Fixed default height in tableheader for Nib2Cib. 2010-03-21 02:54:14 -04:00
Tom Robinson df8357e1fc Add --split option to flatten. Asynchronously load multiple flattened files. 2010-03-20 23:38:40 -07:00
Tom Robinson 35d14939c4 Fix for flatten in Firefox (silly security restriction makes onreadystatechange not readable) 2010-03-20 22:32:11 -07:00
Francisco Ryan Tolmasky I f2c19ad403 Slight fix for collectionView:canDragItemsAtIndexes:withEvent: not passing the correct event.
Reviewed by me.
2010-03-20 20:58:08 -07:00
Francisco Ryan Tolmasky I ed9fee3038 Added collectionView:canDragItemAtIndexes:forEvent:.
Reviewed by me.
2010-03-20 20:56:37 -07:00
Francisco Ryan Tolmasky I 58e31b9cb4 Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-19 12:25:39 -07:00
Francisco Ryan Tolmasky I 401ee3fd94 Added itemAtIndex: to CPCollectionView and updates API names.
Reviewed by me.
2010-03-19 12:24:07 -07:00
Randall Luecke 43b601af9b Fixed TableTest for IE. 2010-03-17 21:07:47 -04:00
Francisco Ryan Tolmasky I 5581dd71fa Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-17 01:17:50 -07:00
Tom Robinson d8fb849691 Refactor objj_eval to work in the browser. Move from CommonJS-specific code to Objective-J proper. 2010-03-16 23:57:37 -07:00
Tom Robinson 5f4281b851 Add default theme to flattened app, "-P" option for specifying other inlined files. 2010-03-16 22:38:30 -07:00
Tom Robinson 24ab176236 Make asyncLoader a configurable option on exports. 2010-03-16 22:38:30 -07:00
Tom Robinson 9c342ca19c Fix objj_eval (used in objj REPL, etc). 2010-03-16 22:38:30 -07:00
Randall Luecke 3ee3acc948 Fixed failed TableCibTest in Firefox. 2010-03-17 00:11:36 -04:00
Randall Luecke 9bdc5fa0fe Various nib2cib improvements on the tableview. 2010-03-16 22:49:38 -04:00
Randall Luecke d7a7d8e2ae Merge branch 'master' of git://github.com/280north/cappuccino 2010-03-16 22:47:40 -04:00
Ross Boucher 5a9682b1bd Remove two calls to a dead function. 2010-03-16 18:13:57 -07:00
Randall Luecke 3c97903ed0 Fixed Nib2Cib selection color for the tableview. 2010-03-16 19:34:04 -04:00
Ross Boucher c9cf21be80 Fix for sizeWithFont: in Internet Explorer. 2010-03-16 16:01:44 -07:00
Tom Robinson f0818d94e9 Typo in window.clearNativeInterval. 2010-03-16 15:44:45 -07:00
Francisco Ryan Tolmasky I 831555cf5a Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-15 02:33:36 -07:00
Randall Luecke e0483e316e Fixed bug with nib2cib tableviews loading incorrect resources. 2010-03-14 17:24:36 -04:00
Ross Boucher c1fe45cbcd Add a way to tell a CPSplitView about a button bar for a specific divider index,
which mitigates the need to use additional effective rect delegate method when
using a split view + button bar.
2010-03-14 12:32:52 -07:00
Ross Boucher ef7ad8ee8e A few minor bug fixes for key/main window handling. 2010-03-13 22:49:06 -08:00
Ross Boucher 0ed7d46926 Add encoding support for CPButtonBar. 2010-03-13 22:49:06 -08:00
Tom Robinson ac69879fba Update flatten to use new file/function caching system. 2010-03-13 21:42:51 -08:00
Tom Robinson 50e779ef5a Add CFHTTPRequest and FileExecutable hooks for inlining files and module functions (for flatten). Removed hook used by flatten. 2010-03-13 21:35:15 -08:00
Tom Robinson 0032af1468 Merge branch 'master' of github.com:280north/cappuccino 2010-03-13 19:05:10 -08:00
Ross Boucher cf1c369dc3 Rewrite of CPButtonBar. Now it will automatically layout the buttons, and the position
and visibility of the resize control is configurable.

Also has class methods for plusButton and minusButton. API subject to change.
2010-03-13 17:37:28 -08:00
Tom Robinson ece7996895 Cleanup flatten, use resourceAtURL instead of manually walking path. 2010-03-13 01:17:47 -08:00
Randall Luecke 3cdfc1192a Fixes flickering issues with CPTableView if you hold the command key and drag. Closes #544 2010-03-13 00:07:00 -05:00
Ross Boucher 8b8998a2b9 Don't encode the search/cancel buttons. They add bloat and complicate the process. 2010-03-12 19:46:05 -08:00
Tom Robinson 677cf9e1df Change FileRequest to always use CFHTTPRequest and make async/sync configurable. Preparation for "flatten" changes. 2010-03-12 19:40:27 -08:00
Ross Boucher a08d4c6a06 Whitespace error. 2010-03-12 18:55:44 -08:00
aburkhalterandRoss Boucher e1e344dad1 Missing semi-colon. 2010-03-12 18:54:05 -08:00
aburkhalterandRoss Boucher b9427f84ae Fixes testShiftIndexesStartingAtIndex. Upward shifting no longer throws. 2010-03-12 18:53:58 -08:00
Andrew BurkhalterandRoss Boucher dc9d79bc3d Adding failing test demonstrating that CPIndexSet throws with negative delta (e.g. shifting indexes at starting point upwards). Simple downward shift example included and working successfully.
Misc method reorganization with test suite so it's a bit more intuitive.
2010-03-12 18:50:35 -08:00
Ross Boucher 503ce5502e Fix nib2cib support for CPSearchField 2010-03-12 18:49:37 -08:00
Tom Robinson 0e4d476d76 Add guard div to protect against iframes consuming events during tracking. 2010-03-12 17:25:19 -08:00
Francisco Ryan Tolmasky I cc2d579bc9 Merge branch '0.8.0' of git@github.com:280north/cappuccino 2010-03-12 03:33:21 -08:00
Tom Robinson 94bf2a36cf Updated flatten to work with new loader changes. 2010-03-11 15:56:58 -08:00
Tom Robinson 63127bf9c3 Fix CFBundle path deprecation warning and absoluteString not found. 2010-03-11 14:35:06 -08:00
Ross Boucher 033765e866 temporary fix for whiteSpace style issue in IE. 2010-03-11 14:28:31 -08:00
Ross Boucher 1634e4562a Update the template files to more modern standards. 2010-03-11 14:28:22 -08:00
Randall Luecke 10b7eb83f1 Fixed previous commit so it doesn't break buttons in the tableview. 2010-03-09 23:52:08 -05:00
Tom Robinson bd21153300 Typo in CI script. 2010-03-09 16:07:39 -08:00
Tom Robinson 4b1bf1fe65 Factor out nightly build portion of CI script so not all branches push builds 2010-03-09 15:32:13 -08:00
Randall Luecke cc2bb8f496 Fixed bug where editable tableview would not honor setEditable:NO for columns unless resized. closes #426 2010-03-09 14:39:26 -05:00
cacaodevandRandall Luecke 20853e3ad7 CPTableView & al. : change CPThemeStateHighlighted to CPThemeStateSelected to avoid conflicts with CPControl -highlight: method. 2010-03-09 11:43:37 -05:00
appdenandRandall Luecke 54549b61e1 Added semi-colons to global vars and removed accidental gloabl variable. 2010-03-09 03:20:00 -05:00
Francisco Ryan Tolmasky I 458481af4e Revert "Pulled @each out into a separate feature branch, so as to not conflict with the 0.8 work: http://github.com/280north/cappuccino/tree/@each ."
This reverts commit 7433c38d92.
2010-02-22 02:25:39 -08:00
Alexander LjungbergandRoss Boucher 3cb3bfc008 Fixed: CPArrayController selectionIndexes returned nil initially rather than an empty index set. 2010-01-08 09:58:54 -08:00
Ross Boucher 3635d0ec26 Bindings Checkpoint. 2009-09-21 13:27:50 -07:00
Ross Boucher 105bb7512f Merge branch 'master' of git@github.com:280north/cappuccino into bindings 2009-09-20 22:55:19 -07:00
Ross Boucher b63e50dacb Fix for the objectValue/value thing in bindings. Removed unnecessary code in CPControl 2009-09-20 19:33:03 -07:00
Ross Boucher 417b5c8b97 Merge branch 'master' into bindings 2009-09-20 18:14:17 -07:00
Francisco Ryan Tolmasky I 08ed16c493 Made CPObjectController's contentObject binding bidirectional.
Reviewed by me.
2009-07-22 23:54:38 -07:00
Francisco Ryan Tolmasky I 734efdf343 Merge branch 'master' into bindings 2009-07-22 19:40:23 -07:00
Francisco Ryan Tolmasky I 1195678893 Removed Framework directories from bindings tests.
Reviewed by me.
2009-07-22 17:54:53 -07:00
Francisco Ryan Tolmasky I 4ad2c2221f Merge branch 'master' into bindings
Conflicts:
	AppKit/CPControl.j
	AppKit/CPSlider.j
	Foundation/CPArray+KVO.j
2009-07-22 16:41:58 -07:00
Ross Boucher 18cf198592 Beginnings of a simple array controller test app. 2009-02-19 01:36:40 -08:00
Ross Boucher 9bbe51fa64 CPArrayController works simply with bindings and arrangedObjects 2009-02-19 01:29:39 -08:00
Ross Boucher 4de3a34a3e CPObjectController now works, as do bindings and CPControls. 2009-02-16 00:37:50 -08:00
Ross Boucher c028425f14 More bindings fixes. 2009-02-09 17:35:25 -08:00
Ross Boucher 7d03d8a58f Some test apps for bindings. 2009-02-07 13:00:27 -07:00
Ross Boucher db0e88d8a7 Various fixes. 2009-02-07 12:59:50 -07:00
Ross Boucher 1b8aca26a3 In progress work on bindings. 2009-02-07 12:55:15 -07:00
Ross Boucher b239053810 First take at CPController, CPObjectController. 2009-02-07 12:55:05 -07:00
Ross Boucher 1acb130be1 Add preliminary support for Key Value Bindings to Cappuccino. 2009-02-07 12:54:59 -07:00
687 changed files with 49874 additions and 8732 deletions
+10 -4
View File
@@ -26,6 +26,7 @@
@import "CPApplication.j"
@import "CPBezierPath.j"
@import "CPBox.j"
@import "CPBrowser.j"
@import "CPButton.j"
@import "CPButtonBar.j"
@import "CPCheckBox.j"
@@ -35,8 +36,8 @@
@import "CPCibLoading.j"
@import "CPCibOutletConnector.j"
@import "CPClipView.j"
@import "CPCollectionViewItem.j"
@import "CPCollectionView.j"
@import "CPCollectionViewItem.j"
@import "CPColor.j"
@import "CPColorPanel.j"
@import "CPColorWell.j"
@@ -52,8 +53,10 @@
@import "CPFont.j"
@import "CPFontManager.j"
@import "CPGeometry.j"
@import "CPGraphics.j"
@import "CPImage.j"
@import "CPImageView.j"
@import "CPKeyBinding.j"
@import "CPMenu.j"
@import "CPMenuItem.j"
@import "CPOpenPanel.j"
@@ -64,20 +67,22 @@
@import "CPProgressIndicator.j"
@import "CPRadio.j"
@import "CPResponder.j"
@import "CPSearchField.j"
@import "CPScrollView.j"
@import "CPScroller.j"
@import "CPScrollView.j"
@import "CPSearchField.j"
@import "CPSecureTextField.j"
@import "CPSegmentedControl.j"
@import "CPShadow.j"
@import "CPSlider.j"
@import "CPSplitView.j"
@import "CPTabView.j"
@import "CPTableColumn.j"
@import "CPTableView.j"
@import "CPTabView.j"
@import "CPText.j"
@import "CPTextField.j"
@import "CPToolbar.j"
@import "CPToolbarItem.j"
@import "CPTokenField.j"
@import "CPTreeNode.j"
@import "CPView.j"
@import "CPViewAnimation.j"
@@ -85,3 +90,4 @@
@import "CPWebView.j"
@import "CPWindow.j"
@import "CPWindowController.j"
@import "CPArrayController.j"
+49 -14
View File
@@ -26,11 +26,16 @@
@import <Foundation/CPIndexSet.j>
@import <Foundation/CPString.j>
@import <AppKit/CPView.j>
#import "CoreGraphics/CGGeometry.h"
@import "CPView.j"
@import "CPButton.j"
/*!
@ingroup appkit
@class CPAccordionViewItem
<p>A CPAccordionViewItem represents a single section of a CPAccordionView.</p>
*/
@implementation CPAccordionViewItem : CPObject
{
CPString _identifier @accessors(property=identifier);
@@ -43,6 +48,10 @@
return [self initWithIdentifier:@""];
}
/*!
Initializes a new CPAccordionViewItem with the specified identifier. This identifier may
then be used in subsequent methods to provide abstract introspection of the CPAccordionView.
*/
- (id)initWithIdentifier:(CPString)anIdentifier
{
self = [super init];
@@ -55,6 +64,25 @@
@end
/*!
@ingroup appkit
@class CPAccordionView
<p>CPAccordionView provides a container for CPAccordionViewItem objects and manages layout state
for all sublayout items.</p>
<strong>Example</strong><br />
<pre>
var myAccordionView = [[CPAccordionView alloc] initWithFrame:CGRectMakeZero()];
var firstItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"firstSection"]];
[firstItem setView:[[CPView alloc] initWithFrame:CGRectMakeZero()]];
var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection"]];
[secondItem setView:[[CPView alloc] initWithFrame:CGRectMakeZero()]];
[myAccordionView addItem:firstItem];
[myAccordionView addItem:secondItem];
[myAccordionView setAutoresizingMask: CPViewWidthSizable | CPViewHeightSizable];
</pre>
*/
@implementation CPAccordionView : CPView
{
CPInteger _dirtyItemIndex;
@@ -64,7 +92,10 @@
CPMutableArray _itemViews;
CPIndexSet _expandedItemIndexes;
}
/*!
Initializes the receiver for usage with the specified bounding rectangle
@return the initialized view
*/
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
@@ -95,13 +126,17 @@
{
return _items;
}
- (void)addItem:(CPAccordionItem)anItem
/*!
Append a CPAccordionViewItem to the receiver. Note that the CPAccordionViewItem must contain
a valid CPView derived component or a TypeError will be generated when the contents of the
ViewItem are disclosed.
*/
- (void)addItem:(CPAccordionViewItem)anItem
{
[self insertItem:anItem atIndex:_items.length];
}
- (void)insertItem:(CPAccordionItem)anItem atIndex:(CPInteger)anIndex
- (void)insertItem:(CPAccordionViewItem)anItem atIndex:(CPInteger)anIndex
{
// FIXME: SHIFT ITEMS RIGHT
[_expandedItemIndexes addIndex:anIndex];
@@ -122,7 +157,7 @@
[self setNeedsLayout];
}
- (void)removeItem:(CPAccordionItem)anItem
- (void)removeItem:(CPAccordionViewItem)anItem
{
[self removeItemAtIndex:[_items indexOfObjectIdenticalTo:anItem]];
}
@@ -178,7 +213,7 @@
if ([itemView isCollapsed])
[self expandItemAtIndex:anIndex];
else
[self collapseItemAtIndex:anIndex];
}
@@ -202,12 +237,12 @@
var itemView = _itemViews[anIndex];
if (!itemView)
return;
if (!isEnabled)
[self collapseItemAtIndex:anIndex];
else
[self expandItemAtIndex:anIndex];
[itemView setEnabled:isEnabled];
}
@@ -235,7 +270,7 @@
{
if (_items.length <= 0)
return [self setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), 0.0)];
if (_dirtyItemIndex === CPNotFound)
return;
@@ -356,7 +391,7 @@
[_contentView setFrameSize:_CGSizeMake(aWidth, contentHeight)];
[self setFrame:_CGRectMake(0.0, aY, aWidth, contentHeight + headerHeight)];
}
}
}
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
@@ -373,7 +408,7 @@
/*
else if (aKeyPath === "itemHeaderPrototype")
{
}
*/
}
+258 -104
View File
@@ -26,39 +26,34 @@
@import <Foundation/CPObject.j>
@import <Foundation/CPString.j>
@import <AppKit/CPApplication.j>
@import <AppKit/CPButton.j>
@import <AppKit/CPColor.j>
@import <AppKit/CPFont.j>
@import <AppKit/CPImage.j>
@import <AppKit/CPImageView.j>
@import <AppKit/CPPanel.j>
@import <AppKit/CPTextField.j>
@import "CPApplication.j"
@import "CPButton.j"
@import "CPColor.j"
@import "CPFont.j"
@import "CPImage.j"
@import "CPImageView.j"
@import "CPPanel.j"
@import "CPTextField.j"
/*
@global
@group CPAlertStyle
*/
CPWarningAlertStyle = 0;
CPWarningAlertStyle = 0;
/*
@global
@group CPAlertStyle
*/
CPInformationalAlertStyle = 1;
CPInformationalAlertStyle = 1;
/*
@global
@group CPAlertStyle
*/
CPCriticalAlertStyle = 2;
var CPAlertWarningImage,
CPAlertInformationImage,
CPAlertErrorImage;
CPCriticalAlertStyle = 2;
/*!
@ingroup appkit
CPAlert is an alert panel that can be displayed modally to present the
user with a message and one or more options.
@@ -74,41 +69,51 @@ var CPAlertWarningImage,
@delegate -(void)alertDidEnd:(CPAlert)theAlert returnCode:(int)returnCode;
Called when the user dismisses the alert by clicking one of the buttons.
@param theAlert the alert panel that the user dismissed
@param returnCode the index of the button that the user clicked (starting from 0,
@param returnCode the index of the button that the user clicked (starting from 0,
representing the first button added to the alert which appears on the
right, 1 representing the next button to the left and so on)
*/
@implementation CPAlert : CPObject
@implementation CPAlert : CPView
{
CPPanel _alertPanel;
CPTextField _messageLabel;
CPTextField _informativeLabel;
CPImageView _alertImageView;
CPAlertStyle _alertStyle;
CPString _windowTitle;
int _windowStyle;
int _buttonCount;
CPArray _buttons;
id _delegate;
SEL _didEndSelector;
id _modalDelegate;
}
+ (void)initialize
+ (CPString)defaultThemeClass
{
if (self != CPAlert)
return;
return @"alert";
}
var bundle = [CPBundle bundleForClass:[self class]];
CPAlertWarningImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-warning.png"]
size:CGSizeMake(32.0, 32.0)];
CPAlertInformationImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-information.png"]
size:CGSizeMake(32.0, 32.0)];
CPAlertErrorImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-error.png"]
size:CGSizeMake(32.0, 32.0)];
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[CGSizeMake(400.0, 110.0), CGInsetMake(15, 15, 15, 50), 6, 10,
CPJustifiedTextAlignment, [CPColor blackColor], [CPFont boldSystemFontOfSize:13.0], [CPNull null], CGSizeMakeZero(),
CPJustifiedTextAlignment, [CPColor blackColor], [CPFont systemFontOfSize:12.0], [CPNull null], CGSizeMakeZero(),
CGPointMake(15, 12),
[CPNull null],
[CPNull null],
[CPNull null]
]
forKeys:[@"size", @"content-inset", @"informative-offset", @"button-offset",
@"message-text-alignment", @"message-text-color", @"message-text-font", @"message-text-shadow-color", @"message-text-shadow-offset",
@"informative-text-alignment", @"informative-text-color", @"informative-text-font", @"informative-text-shadow-color", @"informative-text-shadow-offset",
@"image-offset",
@"information-image",
@"warning-image",
@"error-image"
]];
}
/*!
@@ -118,57 +123,56 @@ var CPAlertWarningImage,
{
if (self = [super init])
{
_buttonCount = 0;
_buttons = [CPArray array];
_alertStyle = CPWarningAlertStyle;
_alertPanel = nil;
_windowStyle = nil;
_didEndSelector = nil;
[self setWindowStyle:nil];
_messageLabel = [CPTextField labelWithTitle:@"Alert"];
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
_informativeLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
}
return self;
}
/*!
Sets the window appearance.
Sets the window appearance. If CPHUDBackgroundWindowMask is set, the default HUD theme
will be activated.
@param styleMask - Either CPHUDBackgroundWindowMask or nil for standard.
*/
- (void)setWindowStyle:(int)styleMask
{
_windowStyle = styleMask;
_alertPanel = [[CPPanel alloc] initWithContentRect:CGRectMake(0.0, 0.0, 400.0, 110.0) styleMask:styleMask ? styleMask | CPTitledWindowMask : CPTitledWindowMask];
[_alertPanel setFloatingPanel:YES];
[_alertPanel center];
[_messageLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]];
[self setTheme:(_windowStyle & CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
var count = [_buttons count];
for(var i=0; i < count; i++)
// We'll need to recreate the panel to get the new window style.
_alertPanel = nil;
}
- (void)_createPanel
{
var frame = CGRectMakeZero();
frame.size = [self currentValueForThemeAttribute:@"size"];
_alertPanel = [[CPPanel alloc] initWithContentRect:frame styleMask:_windowStyle ? _windowStyle | CPTitledWindowMask : CPTitledWindowMask];
var contentView = [_alertPanel contentView],
count = [_buttons count];
if (count)
{
var button = _buttons[i];
[button setFrameSize:CGSizeMake([button frame].size.width, (styleMask == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
[[_alertPanel contentView] addSubview:button];
while (count--)
[contentView addSubview:_buttons[count]];
}
if (!_messageLabel)
{
var bounds = [[_alertPanel contentView] bounds];
else
[self addButtonWithTitle:@"OK"];
_messageLabel = [[CPTextField alloc] initWithFrame:CGRectMake(57.0, 10.0, CGRectGetWidth(bounds) - 73.0, 62.0)];
[_messageLabel setFont:[CPFont boldSystemFontOfSize:13.0]];
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
[_messageLabel setAlignment:CPJustifiedTextAlignment];
[_messageLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)];
}
[[_alertPanel contentView] addSubview:_messageLabel];
[[_alertPanel contentView] addSubview:_alertImageView];
[contentView addSubview:_messageLabel];
[contentView addSubview:_alertImageView];
[contentView addSubview:_informativeLabel];
}
/*!
@@ -231,7 +235,7 @@ var CPAlertWarningImage,
}
/*!
Sets the receivers message text, or title, to a given text.
Sets the receivers message text, or title, to a given text.
@param messageText - Message text for the alert.
*/
- (void)setMessageText:(CPString)messageText
@@ -239,41 +243,157 @@ var CPAlertWarningImage,
[_messageLabel setStringValue:messageText];
}
/*!
Return's the receiver's message text body.
/*!
Returns the receiver's message text body.
*/
- (CPString)messageText
{
return [_messageLabel stringValue];
}
/*!
Sets the receiver's informative text, shown below the message text.
@param informativeText - The informative text.
*/
- (void)setInformativeText:(CPString)informativeText
{
[_informativeLabel setStringValue:informativeText];
}
/*!
Returns the receiver's informative text.
*/
- (CPString)informativeText
{
return [_informativeLabel stringValue];
}
/*!
Adds a button with a given title to the receiver.
Buttons will be added starting from the right hand side of the \c CPAlert panel.
The first button will have the index 0, the second button 1 and so on.
The first button will automatically be given a key equivalent of Return,
and any button titled "Cancel" will be given a key equivalent of Escape.
You really shouldn't need more than 3 buttons.
*/
- (void)addButtonWithTitle:(CPString)title
{
var bounds = [[_alertPanel contentView] bounds],
button = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds) - ((_buttonCount + 1) * 90.0), CGRectGetHeight(bounds) - 34.0, 80.0, (_windowStyle == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
button = [[CPButton alloc] initWithFrame:CGRectMakeZero()],
_buttonCount = [_buttons count];
[button setTitle:title];
[button setTarget:self];
[button setTag:_buttonCount];
[button setAction:@selector(_notifyDelegate:)];
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
[button setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
[button setAction:@selector(_dismissAlert:)];
[[_alertPanel contentView] addSubview:button];
if (_buttonCount == 0)
[_alertPanel setDefaultButton:button];
_buttonCount++;
[_buttons addObject:button];
if (_buttonCount == 0)
[button setKeyEquivalent:CPCarriageReturnCharacter];
else if ([title lowercaseString] === "cancel")
[button setKeyEquivalent:CPEscapeFunctionKey];
else
[button setKeyEquivalent:nil];
[_buttons insertObject:button atIndex:0];
}
- (void)layoutPanel
{
if (!_alertPanel)
[self _createPanel];
var inset = [self currentValueForThemeAttribute:@"content-inset"],
iconOffset = [self currentValueForThemeAttribute:@"image-offset"],
theTitle,
theImage;
switch (_alertStyle)
{
case CPWarningAlertStyle: theImage = [self currentValueForThemeAttribute:@"warning-image"];
theTitle = @"Warning";
break;
case CPInformationalAlertStyle: theImage = [self currentValueForThemeAttribute:@"information-image"];
theTitle = @"Information";
break;
case CPCriticalAlertStyle: theImage = [self currentValueForThemeAttribute:@"error-image"];
theTitle = @"Error";
break;
}
[_alertImageView setImage:theImage];
var imageSize = theImage ? [theImage size] : CGSizeMakeZero();
[_alertImageView setFrame:CGRectMake(iconOffset.x, iconOffset.y, imageSize.width, imageSize.height)];
[_alertPanel setTitle:_windowTitle ? _windowTitle : theTitle];
[_alertPanel setFloatingPanel:YES];
[_alertPanel center];
[_messageLabel setTextColor:[self currentValueForThemeAttribute:@"message-text-color"]];
[_messageLabel setFont:[self currentValueForThemeAttribute:@"message-text-font"]];
[_messageLabel setTextShadowColor:[self currentValueForThemeAttribute:@"message-text-shadow-color"]];
[_messageLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"message-text-shadow-offset"]];
[_messageLabel setAlignment:[self currentValueForThemeAttribute:@"message-text-alignment"]];
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
[_informativeLabel setTextColor:[self currentValueForThemeAttribute:@"informative-text-color"]];
[_informativeLabel setFont:[self currentValueForThemeAttribute:@"informative-text-font"]];
[_informativeLabel setTextShadowColor:[self currentValueForThemeAttribute:@"informative-text-shadow-color"]];
[_informativeLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"informative-text-shadow-offset"]];
[_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping];
// FIXME sizeWithFontCorrection shouldn't be needed.
var bounds = [[_alertPanel contentView] bounds],
offsetX = CGRectGetWidth(bounds) - inset.right,
informativeOffset = [self currentValueForThemeAttribute:@"informative-offset"],
buttonOffset = [self currentValueForThemeAttribute:@"button-offset"],
textWidth = offsetX - inset.left,
messageSize = [([_messageLabel stringValue] || " ") sizeWithFont:[_messageLabel font] inWidth:textWidth],
informationString = [_informativeLabel stringValue],
informativeSize = [(informationString || " ") sizeWithFont:[_informativeLabel font] inWidth:textWidth],
sizeWithFontCorrection = 6.0;
[_messageLabel setFrame:CGRectMake(inset.left, inset.top, textWidth, messageSize.height + sizeWithFontCorrection)];
[_informativeLabel setFrame:CGRectMake(inset.left, CGRectGetMaxY([_messageLabel frame]) + informativeOffset, textWidth, informativeSize.height + sizeWithFontCorrection)];
// Don't let an empty informative label partially cover the buttons.
[_informativeLabel setHidden:!informationString];
var aRepresentativeButton = _buttons[0],
buttonY = MAX(CGRectGetMaxY([_alertImageView frame]), CGRectGetMaxY(informationString ? [_informativeLabel frame] : [_messageLabel frame])) + buttonOffset; // the lower of the bottom of the text and the bottom of the icon.
[aRepresentativeButton setTheme:[self theme]];
[aRepresentativeButton sizeToFit];
// Make the window just tall enough to fit everything. Bit of a hack really.
var minimumSize = [self currentValueForThemeAttribute:@"size"],
desiredHeight = MAX(minimumSize.height, buttonY + CGRectGetHeight([aRepresentativeButton bounds]) + inset.bottom),
deltaY = desiredHeight - CGRectGetHeight(bounds),
frameSize = CGSizeMakeCopy([_alertPanel frame].size);
frameSize.height += deltaY;
[_alertPanel setFrameSize:frameSize];
var count = [_buttons count];
while (count--)
{
var button = _buttons[count];
[button setTheme:[self theme]];
[button sizeToFit];
var buttonBounds = [button bounds],
width = MAX(80.0, CGRectGetWidth(buttonBounds)),
height = CGRectGetHeight(buttonBounds);
offsetX -= width;
[button setFrame:CGRectMake(offsetX, buttonY, width, height)];
offsetX -= 10;
}
}
/*!
@@ -283,34 +403,68 @@ var CPAlertWarningImage,
*/
- (void)runModal
{
var theTitle;
switch (_alertStyle)
{
case CPWarningAlertStyle: [_alertImageView setImage:CPAlertWarningImage];
theTitle = @"Warning";
break;
case CPInformationalAlertStyle: [_alertImageView setImage:CPAlertInformationImage];
theTitle = @"Information";
break;
case CPCriticalAlertStyle: [_alertImageView setImage:CPAlertErrorImage];
theTitle = @"Error";
break;
}
[_alertPanel setTitle:_windowTitle ? _windowTitle : theTitle];
[self layoutPanel];
[CPApp runModalForWindow:_alertPanel];
}
/* @ignore */
- (void)_notifyDelegate:(id)button
{
[CPApp abortModal];
[_alertPanel close];
/*!
Runs the receiver modally as an alert sheet attached to a specified window.
if (_delegate && [_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
[_delegate alertDidEnd:self returnCode:[button tag]];
@param window The parent window for the sheet.
@param modalDelegate The delegate for the modal-dialog session.
@param alertDidEndSelector Message the alert sends to modalDelegate after the sheet is dismissed.
@param contextInfo Contextual data passed to modalDelegate in didEndSelector message.
*/
- (void)beginSheetModalForWindow:(CPWindow)window modalDelegate:(id)modalDelegate didEndSelector:(SEL)alertDidEndSelector contextInfo:(void)contextInfo
{
if (!(_windowStyle & CPDocModalWindowMask))
[self setWindowStyle:CPDocModalWindowMask];
[self layoutPanel];
_didEndSelector = alertDidEndSelector;
_modalDelegate = modalDelegate;
[CPApp beginSheet:_alertPanel modalForWindow:window modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:contextInfo];
}
/*!
Runs the receiver modally as an alert sheet attached to a specified window.
@param window The parent window for the sheet.
*/
- (void)beginSheetModalForWindow:(CPWindow)window
{
if (!(_windowStyle & CPDocModalWindowMask))
[self setWindowStyle:CPDocModalWindowMask];
[self layoutPanel];
[CPApp beginSheet:_alertPanel modalForWindow:window modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
}
- (void)_alertDidEnd:(CPWindow)aSheet returnCode:(CPInteger)returnCode contextInfo:(id)contextInfo
{
if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
[_delegate alertDidEnd:self returnCode:returnCode];
if (_didEndSelector)
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
_didEndSelector = nil;
_modalDelegate = nil;
}
/* @ignore */
- (void)_dismissAlert:(CPButton)button
{
if ([_alertPanel isSheet])
[CPApp endSheet:_alertPanel returnCode:[button tag]];
else
{
[CPApp abortModal];
[_alertPanel close];
[self _alertDidEnd:nil returnCode:[button tag] contextInfo:nil];
}
}
@end
+27 -27
View File
@@ -48,14 +48,14 @@ CPAnimationLinear = 3;
ACTUAL_FRAME_RATE = 0;
/*!
/*!
@ingroup appkit
@class CPAnimation
Manages an animation. Contains timing and progress information.
@par Delegate Methods
@delegate -(BOOL)animationShouldStart:(CPAnimation)animation;
Called at the beginning of \c -startAnimation.
@param animation the animation that will start
@@ -81,13 +81,13 @@ ACTUAL_FRAME_RATE = 0;
{
CPTimeInterval _lastTime;
CPTimeInterval _duration;
CPAnimationCurve _animationCurve;
CAMediaTimingFunction _timingFunction;
float _frameRate;
float _progress;
id _delegate;
CPTimer _timer;
}
@@ -101,7 +101,7 @@ ACTUAL_FRAME_RATE = 0;
- (id)initWithDuration:(float)aDuration animationCurve:(CPAnimationCurve)anAnimationCurve
{
self = [super init];
if (self)
{
_progress = 0.0;
@@ -110,14 +110,14 @@ ACTUAL_FRAME_RATE = 0;
[self setAnimationCurve:anAnimationCurve];
}
return self;
}
/*!
Sets the animation's pace.
@param anAnimationCurve the animation's pace
@throws CPInvalidArgumentException if an invalid animation curve is specified
@throws CPInvalidArgumentException if an invalid animation curve is specified
*/
- (void)setAnimationCurve:(CPAnimationCurve)anAnimationCurve
{
@@ -125,13 +125,13 @@ ACTUAL_FRAME_RATE = 0;
{
case CPAnimationEaseInOut: timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut;
break;
case CPAnimationEaseIn: timingFunctionName = kCAMediaTimingFunctionEaseIn;
break;
case CPAnimationEaseOut: timingFunctionName = kCAMediaTimingFunctionEaseOut;
break;
case CPAnimationLinear: timingFunctionName = kCAMediaTimingFunctionLinear;
break;
@@ -139,7 +139,7 @@ ACTUAL_FRAME_RATE = 0;
reason:"Invalid value provided for animation curve"];
break;
}
_animationCurve = anAnimationCurve;
_timingFunction = [CAMediaTimingFunction functionWithName:timingFunctionName];
}
@@ -161,7 +161,7 @@ ACTUAL_FRAME_RATE = 0;
{
if (aDuration < 0)
[CPException raise:CPInvalidArgumentException reason:"aDuration can't be negative"];
_duration = aDuration;
}
@@ -182,7 +182,7 @@ ACTUAL_FRAME_RATE = 0;
{
if (frameRate < 0)
[CPException raise:CPInvalidArgumentException reason:"frameRate can't be negative"];
_frameRate = frameRate;
}
@@ -221,13 +221,13 @@ ACTUAL_FRAME_RATE = 0;
// If we're already animating, or our delegate stops us, animate.
if (_timer || _delegate && [_delegate respondsToSelector:@selector(animationShouldStart:)] && ![_delegate animationShouldStart:self])
return;
if (_progress === 1.0)
_progress = 0.0;
ACTUAL_FRAME_RATE = 0;
_lastTime = new Date();
_timer = [CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(animationTimerDidFire:) userInfo:nil repeats:YES];
}
@@ -242,14 +242,14 @@ ACTUAL_FRAME_RATE = 0;
_lastTime = currentTime;
++ACTUAL_FRAME_RATE;
[self setCurrentProgress:progress];
if (progress === 1.0)
{
[_timer invalidate];
_timer = nil;
if ([_delegate respondsToSelector:@selector(animationDidEnd:)])
[_delegate animationDidEnd:self];
}
@@ -262,10 +262,10 @@ ACTUAL_FRAME_RATE = 0;
{
if (!_timer)
return;
[_timer invalidate];
_timer = nil;
if ([_delegate respondsToSelector:@selector(animationDidStop:)])
[_delegate animationDidStop:self];
}
@@ -302,16 +302,16 @@ ACTUAL_FRAME_RATE = 0;
- (float)currentValue
{
var t = [self currentProgress];
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
return [_delegate animation:self valueForProgress:t];
var c1 = [],
c2 = [];
[_timingFunction getControlPointAtIndex:1 values:c1];
[_timingFunction getControlPointAtIndex:2 values:c2];
return CubicBezierAtTime(t,c1[0],c1[1],c2[0],c2[1],_duration);
}
@@ -332,7 +332,7 @@ var CubicBezierAtTime = function CubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration)
function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));};
// Given an x value, find a parametric value it came from.
function solveCurveX(x,epsilon) {var t0,t1,t2,x2,d2,i;
function fabs(n) {if(n>=0) {return n;}else {return 0-n;}};
function fabs(n) {if(n>=0) {return n;}else {return 0-n;}};
// First try a few iterations of Newton's method -- normally very fast.
for(t2=x, i=0; i<8; i++) {x2=sampleCurveX(t2)-x; if(fabs(x2)<epsilon) {return t2;} d2=sampleCurveDerivativeX(t2); if(fabs(d2)<1e-6) {break;} t2=t2-x2/d2;}
// Fall back to the bisection method for reliability.
+219 -218
View File
@@ -53,7 +53,7 @@ CPRunStoppedResponse = -1000;
CPRunAbortedResponse = -1001;
CPRunContinuesResponse = -1002;
/*!
/*!
@ingroup appkit
@class CPApplication
@@ -61,7 +61,7 @@ CPRunContinuesResponse = -1002;
Every GUI application has exactly one instance of CPApplication (or of a custom subclass of
CPApplication). Your program's main() function can create that instance by calling the
\c CPApplicationMain function. A simple example looks like this:
<pre>
function main(args, namedArgs)
{
@@ -81,25 +81,25 @@ CPRunContinuesResponse = -1002;
@implementation CPApplication : CPResponder
{
CPArray _eventListeners;
CPEvent _currentEvent;
CPArray _windows;
CPWindow _keyWindow;
CPWindow _mainWindow;
CPWindow _previousKeyWindow;
CPWindow _previousMainWindow;
CPMenu _mainMenu;
CPDocumentController _documentController;
CPModalSession _currentSession;
//
id _delegate;
BOOL _finishedLaunching;
BOOL _isActive;
CPDictionary _namedArgs;
CPArray _args;
CPString _fullArgsString;
@@ -107,6 +107,8 @@ CPRunContinuesResponse = -1002;
CPImage _applicationIconImage;
CPPanel _aboutPanel;
CPThemeBlend _themeBlend @accessors(property=themeBlend);
}
/*!
@@ -118,7 +120,7 @@ CPRunContinuesResponse = -1002;
{
if (!CPApp)
CPApp = [[CPApplication alloc] init];
return CPApp;
}
@@ -130,73 +132,18 @@ CPRunContinuesResponse = -1002;
- (id)init
{
self = [super init];
CPApp = self;
if (self)
{
_eventListeners = [];
_windows = [];
[_windows addObject:nil];
// FIXME: This should be read from the cib.
_mainMenu = [[CPMenu alloc] initWithTitle:@"MainMenu"];
// FIXME: We should implement autoenabling.
[_mainMenu setAutoenablesItems:NO];
var bundle = [CPBundle bundleForClass:[CPApplication class]],
newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"N"];
[newMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/New.png"] size:CGSizeMake(16.0, 16.0)]];
[newMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/NewHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[_mainMenu addItem:newMenuItem];
var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"O"];
[openMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Open.png"] size:CGSizeMake(16.0, 16.0)]];
[openMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/OpenHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[_mainMenu addItem:openMenuItem];
var saveMenu = [[CPMenu alloc] initWithTitle:@"Save"],
saveMenuItem = [[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:nil];
[saveMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Save.png"] size:CGSizeMake(16.0, 16.0)]];
[saveMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/SaveHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"S"]];
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:nil]];
[saveMenuItem setSubmenu:saveMenu];
[_mainMenu addItem:saveMenuItem];
var editMenuItem = [[CPMenuItem alloc] initWithTitle:@"Edit" action:nil keyEquivalent:nil],
editMenu = [[CPMenu alloc] initWithTitle:@"Edit"],
undoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:CPUndoKeyEquivalent],
redoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:CPRedoKeyEquivalent];
[undoMenuItem setKeyEquivalentModifierMask:CPUndoKeyEquivalentModifierMask];
[redoMenuItem setKeyEquivalentModifierMask:CPRedoKeyEquivalentModifierMask];
[editMenu addItem:undoMenuItem];
[editMenu addItem:redoMenuItem];
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"X"]],
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"C"]],
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"V"]];
[editMenuItem setSubmenu:editMenu];
[editMenuItem setHidden:YES];
[_mainMenu addItem:editMenuItem];
[_mainMenu addItem:[CPMenuItem separatorItem]];
}
return self;
}
@@ -212,85 +159,46 @@ CPRunContinuesResponse = -1002;
{
if (_delegate == aDelegate)
return;
var defaultCenter = [CPNotificationCenter defaultCenter];
var defaultCenter = [CPNotificationCenter defaultCenter],
delegateNotifications =
[
CPApplicationWillFinishLaunchingNotification, @selector(applicationWillFinishLaunching:),
CPApplicationDidFinishLaunchingNotification, @selector(applicationDidFinishLaunching:),
CPApplicationWillBecomeActiveNotification, @selector(applicationWillBecomeActive:),
CPApplicationDidBecomeActiveNotification, @selector(applicationDidBecomeActive:),
CPApplicationWillResignActiveNotification, @selector(applicationWillResignActive:),
CPApplicationDidResignActiveNotification, @selector(applicationDidResignActive:),
CPApplicationWillTerminateNotification, @selector(applicationWillTerminate:)
],
count = [delegateNotifications count];
if (_delegate)
{
[defaultCenter
removeObserver:_delegate
name:CPApplicationWillFinishLaunchingNotification
object:self];
var index = 0;
[defaultCenter
removeObserver:_delegate
name:CPApplicationDidFinishLaunchingNotification
object:self];
for (; index < count; index += 2)
{
var notificationName = delegateNotifications[index],
selector = delegateNotifications[index + 1];
[defaultCenter
removeObserver:_delegate
name:CPApplicationWillBecomeActiveNotification
object:self];
[defaultCenter
removeObserver:_delegate
name:CPApplicationDidBecomeActiveNotification
object:self];
[defaultCenter
removeObserver:_delegate
name:CPApplicationWillResignActiveNotification
object:self];
[defaultCenter
removeObserver:_delegate
name:CPApplicationDidResignActiveNotification
object:self];
if ([_delegate respondsToSelector:selector])
[defaultCenter removeObserver:_delegate name:notificationName object:self];
}
}
_delegate = aDelegate;
if ([_delegate respondsToSelector:@selector(applicationWillFinishLaunching:)])
[defaultCenter
addObserver:_delegate
selector:@selector(applicationWillFinishLaunching:)
name:CPApplicationWillFinishLaunchingNotification
object:self];
if ([_delegate respondsToSelector:@selector(applicationDidFinishLaunching:)])
[defaultCenter
addObserver:_delegate
selector:@selector(applicationDidFinishLaunching:)
name:CPApplicationDidFinishLaunchingNotification
object:self];
if ([_delegate respondsToSelector:@selector(applicationWillBecomeActive:)])
[defaultCenter
addObserver:_delegate
selector:@selector(applicationWillBecomeActive:)
name:CPApplicationWillBecomeActiveNotification
object:self];
var index = 0;
if ([_delegate respondsToSelector:@selector(applicationDidBecomeActive:)])
[defaultCenter
addObserver:_delegate
selector:@selector(applicationDidBecomeActive:)
name:CPApplicationDidBecomeActiveNotification
object:self];
for (; index < count; index += 2)
{
var notificationName = delegateNotifications[index],
selector = delegateNotifications[index + 1];
if ([_delegate respondsToSelector:@selector(applicationWillResignActive:)])
[defaultCenter
addObserver:_delegate
selector:@selector(applicationWillResignActive:)
name:CPApplicationWillResignActiveNotification
object:self];
if ([_delegate respondsToSelector:@selector(applicationDidResignActive:)])
[defaultCenter
addObserver:_delegate
selector:@selector(applicationDidResignActive:)
name:CPApplicationDidResignActiveNotification
object:self];
if ([_delegate respondsToSelector:selector])
[defaultCenter addObserver:_delegate selector:selector name:notificationName object:self];
}
}
/*!
@@ -316,28 +224,28 @@ CPRunContinuesResponse = -1002;
// We also want to set the default cursor on the body, so that buttons and things don't have an iBeam
[[CPCursor arrowCursor] set];
var bundle = [CPBundle mainBundle],
types = [bundle objectForInfoDictionaryKey:@"CPBundleDocumentTypes"];
if ([types count] > 0)
_documentController = [CPDocumentController sharedDocumentController];
var delegateClassName = [bundle objectForInfoDictionaryKey:@"CPApplicationDelegateClass"];
if (delegateClassName)
{
var delegateClass = objj_getClass(delegateClassName);
if (delegateClass)
if ([_documentController class] == delegateClass)
[self setDelegate:_documentController];
else
[self setDelegate:[[delegateClass alloc] init]];
}
var defaultCenter = [CPNotificationCenter defaultCenter];
[defaultCenter
postNotificationName:CPApplicationWillFinishLaunchingNotification
object:self];
@@ -369,6 +277,10 @@ CPRunContinuesResponse = -1002;
- (void)terminate:(id)aSender
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPApplicationWillTerminateNotification
object:self];
if (![CPPlatform isBrowser])
{
[[CPDocumentController sharedDocumentController] closeAllDocumentsWithDelegate:self
@@ -414,7 +326,9 @@ CPRunContinuesResponse = -1002;
applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"],
copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"];
var aboutPanelController = [[CPWindowController alloc] initWithWindowCibName:@"AboutPanel"],
var aboutPanelPath = [[CPBundle bundleForClass:[CPWindowController class]] pathForResource:@"AboutPanel.cib"],
aboutPanelController = [CPWindowController alloc],
aboutPanelController = [aboutPanelController initWithWindowCibPath:aboutPanelPath owner:aboutPanelController],
aboutPanel = [aboutPanelController window],
contentView = [aboutPanel contentView],
imageView = [contentView viewWithTag:1],
@@ -422,14 +336,14 @@ CPRunContinuesResponse = -1002;
versionLabel = [contentView viewWithTag:3],
copyrightLabel = [contentView viewWithTag:4],
standardPath = [[CPBundle bundleForClass:[self class]] pathForResource:@"standardApplicationIcon.png"];
// FIXME move this into the CIB eventually
[applicationLabel setFont:[CPFont boldSystemFontOfSize:14.0]];
[applicationLabel setAlignment:CPCenterTextAlignment];
[versionLabel setAlignment:CPCenterTextAlignment];
[copyrightLabel setAlignment:CPCenterTextAlignment];
[imageView setImage:applicationIcon || [[CPImage alloc] initWithContentsOfFile:standardPath
[imageView setImage:applicationIcon || [[CPImage alloc] initWithContentsOfFile:standardPath
size:CGSizeMake(256, 256)]];
[applicationLabel setStringValue:applicationTitle || ""];
@@ -533,10 +447,10 @@ CPRunContinuesResponse = -1002;
return;
// raise exception;
}
_currentSession._state = aCode;
_currentSession = _currentSession._previous;
// if (aCode == CPRunAbortedResponse)
[self _removeRunModalLoop];
}
@@ -545,12 +459,12 @@ CPRunContinuesResponse = -1002;
- (void)_removeRunModalLoop
{
var count = _eventListeners.length;
while (count--)
if (_eventListeners[count]._callback === _CPRunModalLoop)
{
_eventListeners.splice(count, 1);
return;
}
}
@@ -588,12 +502,13 @@ CPRunContinuesResponse = -1002;
{
aModalSession._previous = _currentSession;
_currentSession = aModalSession;
var theWindow = aModalSession._window;
[theWindow center];
[theWindow makeKeyAndOrderFront:self];
[theWindow makeKeyWindow];
[theWindow orderFront:self];
// [theWindow._bridge _obscureWindowsBelowModalWindow];
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
@@ -607,7 +522,7 @@ CPRunContinuesResponse = -1002;
{
if (!_currentSession)
return nil;
return _currentSession._window;
}
@@ -652,7 +567,7 @@ CPRunContinuesResponse = -1002;
{
if (_eventListeners[_eventListeners.length - 1]._mask & (1 << [anEvent type]))
_eventListeners.pop()._callback(anEvent);
return;
}
@@ -704,7 +619,11 @@ CPRunContinuesResponse = -1002;
*/
- (CPArray)orderedWindows
{
#if PLATFORM(DOM)
return CPWindowObjectList();
#else
return [];
#endif
}
- (void)hide:(id)aSender
@@ -763,11 +682,11 @@ CPRunContinuesResponse = -1002;
if ([super tryToPerform:anAction with:anObject])
return YES;
if([_delegate respondsToSelector:anAction])
if ([_delegate respondsToSelector:anAction])
{
[_delegate performSelector:anAction withObject:anObject];
return YES;
}
@@ -787,9 +706,9 @@ CPRunContinuesResponse = -1002;
if (!target)
return NO;
[target performSelector:anAction withObject:aSender];
return YES;
}
@@ -808,10 +727,10 @@ CPRunContinuesResponse = -1002;
{
if (!anAction)
return nil;
if (aTarget)
return aTarget;
return [self targetForAction:anAction];
}
@@ -836,28 +755,28 @@ CPRunContinuesResponse = -1002;
{
var responder = [aWindow firstResponder],
checkWindow = YES;
while (responder)
{
if ([responder respondsToSelector:anAction])
return responder;
if (responder == aWindow)
checkWindow = NO;
responder = [responder nextResponder];
}
if (checkWindow && [aWindow respondsToSelector:anAction])
return aWindow;
var delegate = [aWindow delegate];
if ([delegate respondsToSelector:anAction])
return delegate;
var windowController = [aWindow windowController];
if ([windowController respondsToSelector:anAction])
return windowController;
@@ -873,7 +792,7 @@ CPRunContinuesResponse = -1002;
Checks for a target in the following order:
<ol>
<li>a responder from the key window</li>
<li>a responder frmo the main window</li>
<li>a responder from the main window</li>
<li>the CPApplication instance</li>
<li>the application delegate</li>
<li>the document controller</li>
@@ -886,34 +805,32 @@ CPRunContinuesResponse = -1002;
{
if (!anAction)
return nil;
var target = [self _targetForWindow:[self keyWindow] action:anAction];
if (target)
return target;
target = [self _targetForWindow:[self mainWindow] action:anAction];
if (target)
return target;
if ([self respondsToSelector:anAction])
return self;
if ([_delegate respondsToSelector:anAction])
return _delegate;
if ([_documentController respondsToSelector:anAction])
return _documentController;
return nil;
}
- (void)setCallback:(Function)aCallback forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
{
_eventListeners.push(_CPEventListenerMake(aMask, aCallback));
if (_eventListeners.length == 3) objj_debug_print_backtrace();
}
- (CPEvent)setTarget:(id)aTarget selector:(SEL)aSelector forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
@@ -937,30 +854,31 @@ CPRunContinuesResponse = -1002;
@param aContextInfo
*/
- (void)beginSheet:(CPWindow)aSheet modalForWindow:(CPWindow)aWindow modalDelegate:(id)aModalDelegate didEndSelector:(SEL)aDidEndSelector contextInfo:(id)aContextInfo
{
{
var styleMask = [aSheet styleMask];
if (!(styleMask & CPDocModalWindowMask))
{
[CPException raise:CPInternalInconsistencyException reason:@"Currently only CPDocModalWindowMask style mask is supported for attached sheets"];
return;
}
[aWindow orderFront:self];
[aSheet setPlatformWindow:[aWindow platformWindow]];
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
}
- (void)endSheet:(CPWindow)sheet returnCode:(int)returnCode
{
var count = [_windows count];
while (--count >= 0)
{
var aWindow = [_windows objectAtIndex:count];
var context = aWindow._sheetContext;
var aWindow = [_windows objectAtIndex:count],
context = aWindow._sheetContext;
if (context != nil && context["sheet"] === sheet)
{
context["returnCode"] = returnCode;
context["returnCode"] = returnCode;
[aWindow _detachSheetWindow];
return;
}
@@ -974,40 +892,40 @@ CPRunContinuesResponse = -1002;
- (CPArray)arguments
{
if(_fullArgsString !== window.location.hash)
if (_fullArgsString !== window.location.hash)
[self _reloadArguments];
return _args;
}
- (void)setArguments:(CPArray)args
{
if(!args || args.length == 0)
if (!args || args.length == 0)
{
_args = [];
window.location.hash = @"#";
return;
}
if([args class] != CPArray)
if ([args class] != CPArray)
args = [CPArray arrayWithObject:args];
_args = args;
var toEncode = [_args copy];
for(var i=0, count = toEncode.length; i<count; i++)
for (var i = 0, count = toEncode.length; i < count; i++)
toEncode[i] = encodeURIComponent(toEncode[i]);
var hash = [toEncode componentsJoinedByString:@"/"];
window.location.hash = @"#" + hash;
}
- (void)_reloadArguments
{
_fullArgsString = window.location.hash;
if (_fullArgsString.length)
{
var args = _fullArgsString.substring(1).split("/");
@@ -1042,18 +960,18 @@ CPRunContinuesResponse = -1002;
- (void)_willBecomeActive
{
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillBecomeActiveNotification
object:self
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillBecomeActiveNotification
object:self
userInfo:nil];
}
- (void)_didBecomeActive
{
if (![self keyWindow] && _previousKeyWindow &&
if (![self keyWindow] && _previousKeyWindow &&
[[self windows] indexOfObjectIdenticalTo:_previousKeyWindow] !== CPNotFound)
[_previousKeyWindow makeKeyWindow];
if (![self mainWindow] && _previousMainWindow &&
if (![self mainWindow] && _previousMainWindow &&
[[self windows] indexOfObjectIdenticalTo:_previousMainWindow] !== CPNotFound)
[_previousMainWindow makeMainWindow];
@@ -1067,15 +985,15 @@ CPRunContinuesResponse = -1002;
_previousKeyWindow = nil;
_previousMainWindow = nil;
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidBecomeActiveNotification
object:self
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidBecomeActiveNotification
object:self
userInfo:nil];
}
- (void)_willResignActive
{
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillResignActiveNotification
object:self
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillResignActiveNotification
object:self
userInfo:nil];
}
@@ -1096,14 +1014,13 @@ CPRunContinuesResponse = -1002;
[_previousMainWindow resignMainWindow];
}
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidResignActiveNotification
object:self
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidResignActiveNotification
object:self
userInfo:nil];
}
+ (CPString)defaultThemeName
{
// FIXME: don't hardcode
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
}
@@ -1119,13 +1036,14 @@ var _CPEventListenerMake = function(anEventMask, aCallback)
return { _mask:anEventMask, _callback:aCallback };
}
var _CPRunModalLoop = function(anEvent)
// Make this a global for use in CPPlatformWindow+DOM.j.
_CPRunModalLoop = function(anEvent)
{
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
var theWindow = [anEvent window],
modalSession = CPApp._currentSession;
if (theWindow == modalSession._window || [theWindow worksWhenModal])
[theWindow sendEvent:anEvent];
}
@@ -1139,6 +1057,13 @@ var _CPRunModalLoop = function(anEvent)
function CPApplicationMain(args, namedArgs)
{
#if PLATFORM(DOM)
// hook to allow recorder, etc to manipulate things before starting AppKit
if (window.parent !== window && typeof window.parent._childAppIsStarting === "function")
window.parent._childAppIsStarting(window);
#endif
var mainBundle = [CPBundle mainBundle],
principalClass = [mainBundle principalClass];
@@ -1190,8 +1115,15 @@ var _CPAppBootstrapperActions = nil;
+ (BOOL)loadDefaultTheme
{
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName] + ".blend"]];
var defaultThemeName = [CPApplication defaultThemeName],
themeURL = nil;
if (defaultThemeName === @"Aristo")
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:defaultThemeName + @".blend"];
else
themeURL = [[CPBundle mainBundle] pathForResource:defaultThemeName + @".blend"];
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:themeURL];
[blend loadWithDelegate:self];
return YES;
@@ -1199,6 +1131,7 @@ var _CPAppBootstrapperActions = nil;
+ (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend
{
[[CPApplication sharedApplication] setThemeBlend:aThemeBlend];
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
[self performActions];
@@ -1217,18 +1150,86 @@ var _CPAppBootstrapperActions = nil;
return YES;
}
else
[self loadCiblessBrowserMainMenu];
return NO;
}
+ (void)loadCiblessBrowserMainMenu
{
var mainMenu = [[CPMenu alloc] initWithTitle:@"MainMenu"];
// FIXME: We should implement autoenabling.
[mainMenu setAutoenablesItems:NO];
var bundle = [CPBundle bundleForClass:[CPApplication class]],
newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"n"];
[newMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/New.png"] size:CGSizeMake(16.0, 16.0)]];
[newMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/NewHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[mainMenu addItem:newMenuItem];
var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"o"];
[openMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Open.png"] size:CGSizeMake(16.0, 16.0)]];
[openMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/OpenHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[mainMenu addItem:openMenuItem];
var saveMenu = [[CPMenu alloc] initWithTitle:@"Save"],
saveMenuItem = [[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:nil];
[saveMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Save.png"] size:CGSizeMake(16.0, 16.0)]];
[saveMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/SaveHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"s"]];
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:nil]];
[saveMenuItem setSubmenu:saveMenu];
[mainMenu addItem:saveMenuItem];
var editMenuItem = [[CPMenuItem alloc] initWithTitle:@"Edit" action:nil keyEquivalent:nil],
editMenu = [[CPMenu alloc] initWithTitle:@"Edit"],
undoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:CPUndoKeyEquivalent],
redoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:CPRedoKeyEquivalent];
[undoMenuItem setKeyEquivalentModifierMask:CPUndoKeyEquivalentModifierMask];
[redoMenuItem setKeyEquivalentModifierMask:CPRedoKeyEquivalentModifierMask];
[editMenu addItem:undoMenuItem];
[editMenu addItem:redoMenuItem];
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"]],
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]],
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"]];
[editMenuItem setSubmenu:editMenu];
[editMenuItem setHidden:YES];
[mainMenu addItem:editMenuItem];
[mainMenu addItem:[CPMenuItem separatorItem]];
[CPApp setMainMenu:mainMenu];
}
+ (void)cibDidFinishLoading:(CPCib)aCib
{
[self performActions];
}
+ (void)cibDidFailToLoad:(CPCib)aCib
{
throw new Error("Could not load main cib file (Did you forget to nib2cib it?).");
}
+ (void)reset
{
_CPAppBootstrapperActions = nil;
_CPAppBootstrapperActions = nil;
}
@end
+675
View File
@@ -0,0 +1,675 @@
/*
* CPArrayController.j
* AppKit
*
* Adapted from Cocotron, by Johannes Fortmann
*
* Created by Ross Boucher.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPIndexSet.j>
@import "CPObjectController.j"
@import "CPKeyValueBinding.j"
@implementation CPArrayController : CPObjectController
{
BOOL _avoidsEmptySelection;
BOOL _clearsFilterPredicateOnInsertion;
BOOL _filterRestrictsInsertion;
BOOL _preservesSelection;
BOOL _selectsInsertedObjects;
BOOL _alwaysUsesMultipleValuesMarker;
id _selectionIndexes;
id _sortDescriptors;
id _filterPredicate;
id _arrangedObjects;
}
+ (void)initialize
{
if (self !== [CPArrayController class])
return;
[self exposeBinding:@"contentArray"];
[self exposeBinding:@"contentSet"];
}
+ (CPSet)keyPathsForValuesAffectingContentArray
{
return [CPSet setWithObjects:"content"];
}
+ (CPSet)keyPathsForValuesAffectingArrangedObjects
{
return [CPSet setWithObjects:"content", "filterPredicate", "sortDescriptors"];
}
+ (CPSet)keyPathsForValuesAffectingSelection
{
return [CPSet setWithObjects:"selectionIndexes"];
}
+ (CPSet)keyPathsForValuesAffectingSelectionIndex
{
return [CPSet setWithObjects:"selectionIndexes"];
}
+ (CPSet)keyPathsForValuesAffectingSelectionIndexes
{
// When the arranged objects change, selection preservation may cause the indexes
// to change.
return [CPSet setWithObjects:"arrangedObjects"];
}
+ (CPSet)keyPathsForValuesAffectingSelectedObjects
{
// Don't need to depend on arrangedObjects here because selectionIndexes already does.
return [CPSet setWithObjects:"selectionIndexes"];
}
+ (CPSet)keyPathsForValuesAffectingCanRemove
{
return [CPSet setWithObjects:"selectionIndexes"];
}
+ (CPSet)keyPathsForValuesAffectingCanSelectNext
{
return [CPSet setWithObjects:"selectionIndexes"];
}
+ (CPSet)keyPathsForValuesAffectingCanSelectPrevious
{
return [CPSet setWithObjects:"selectionIndexes"];
}
- (id)init
{
self = [super init];
if (self)
{
_selectionIndexes = [CPIndexSet indexSet];
}
return self;
}
- (void)prepareContent
{
[self _setContentArray:[[self newObject]]];
}
- (BOOL)preservesSelection
{
return _preservesSelection;
}
- (void)setPreservesSelection:(BOOL)value
{
_preservesSelection = value;
}
- (BOOL)selectsInsertedObjects
{
return _selectsInsertedObjects;
}
- (void)setSelectsInsertedObjects:(BOOL)value
{
_selectsInsertedObjects = value;
}
- (BOOL)avoidsEmptySelection
{
return _avoidsEmptySelection;
}
- (void)setAvoidsEmptySelection:(BOOL)value
{
_avoidsEmptySelection = value;
}
- (void)setContent:(id)value
{
if (value === nil)
value = [];
if (![value isKindOfClass:[CPArray class]])
value = [value];
var oldSelectedObjects = nil,
oldSelectionIndexes = nil;
if ([self preservesSelection])
oldSelectedObjects = [self selectedObjects];
else
oldSelectionIndexes = [self selectionIndexes];
/*
When the contents are changed, the selected indexes may no longer refer to the
same items. This would cause problems when setSelectedObjects is called below.
Any KVO observation would try to retrieve the 'before' value which could be
wrong or even throw an exception for no longer existing indexes.
To avoid that, use the internal __setSelectedObjects which fires no notifications.
The selectionIndexes notifications will fire later since they depend on the
content key. This pattern is also applied for many other methods throughout this
class.
*/
if (_clearsFilterPredicateOnInsertion)
[self willChangeValueForKey:@"filterPredicate"];
// Don't use [super setContent:] as that would fire the contentObject change.
// We need to be in control of when notifications fire.
_contentObject = value;
if (_clearsFilterPredicateOnInsertion)
[self __setFilterPredicate:nil]; // Causes a _rearrangeObjects.
else
[self _rearrangeObjects];
if ([self preservesSelection])
[self __setSelectedObjects:oldSelectedObjects];
else
[self __setSelectionIndexes:oldSelectionIndexes];
if (_clearsFilterPredicateOnInsertion)
[self didChangeValueForKey:@"filterPredicate"];
}
- (void)_setContentArray:(id)anArray
{
[self setContent:anArray];
}
- (void)_setContentSet:(id)aSet
{
[self setContent:aSet];
}
- (id)contentArray
{
return [self content];
}
- (id)contentSet
{
return [self content];
}
- (CPArray)arrangeObjects:(CPArray)objects
{
var filterPredicate = [self filterPredicate],
sortDescriptors = [self sortDescriptors];
if (filterPredicate && sortDescriptors)
{
var sortedObjects = [objects filteredArrayUsingPredicate:filterPredicate];
[sortedObjects sortUsingDescriptors:sortDescriptors];
return sortedObjects;
}
else if (filterPredicate)
return [objects filteredArrayUsingPredicate:filterPredicate];
else if (sortDescriptors)
return [objects sortedArrayUsingDescriptors:sortDescriptors];
return [objects copy];
}
- (void)rearrangeObjects
{
[self willChangeValueForKey:@"arrangedObjects"];
[self _rearrangeObjects];
[self didChangeValueForKey:@"arrangedObjects"];
}
/*
Like rearrangeObjects but don't fire any change notifications.
@ignore
*/
- (void)_rearrangeObjects
{
/*
Rearranging reapplies the selection criteria and may cause objects to disappear,
so take care of the selection.
*/
var oldSelectedObjects = nil,
oldSelectionIndexes = nil;
if ([self preservesSelection])
oldSelectedObjects = [self selectedObjects];
else
oldSelectionIndexes = [self selectionIndexes];
[self __setArrangedObjects:[self arrangeObjects:[self contentArray]]];
if ([self preservesSelection])
[self __setSelectedObjects:oldSelectedObjects];
else
[self __setSelectionIndexes:oldSelectionIndexes];
}
- (void)__setArrangedObjects:(id)value
{
if (_arrangedObjects === value)
return;
_arrangedObjects = [[_CPObservableArray alloc] initWithArray:value];
}
- (id)arrangedObjects
{
return _arrangedObjects;
}
- (CPArray)sortDescriptors
{
return _sortDescriptors;
}
- (void)setSortDescriptors:(CPArray)value
{
if (_sortDescriptors === value)
return;
_sortDescriptors = [value copy];
// Use the non-notification version since arrangedObjects already depends
// on sortDescriptors.
[self _rearrangeObjects];
}
- (CPPredicate)filterPredicate
{
return _filterPredicate;
}
- (void)setFilterPredicate:(CPPredicate)value
{
[self __setFilterPredicate:value];
}
/*
Like setFilterPredicate but don't fire any change notifications.
@ignore
*/
- (void)__setFilterPredicate:(CPPredicate)value
{
if (_filterPredicate === value)
return;
_filterPredicate = value;
// Use the non-notification version since arrangedObjects already depends
// on filterPredicate.
[self _rearrangeObjects];
}
- (BOOL)alwaysUsesMultipleValuesMarker
{
return _alwaysUsesMultipleValuesMarker;
}
//Selection
- (unsigned)selectionIndex
{
return [_selectionIndexes firstIndex];
}
- (BOOL)setSelectionIndex:(unsigned)index
{
return [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
}
- (CPIndexSet)selectionIndexes
{
return _selectionIndexes;
}
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
{
[self _selectionWillChange]
[self __setSelectionIndexes:indexes];
[self _selectionDidChange];
}
/*
Like setSelectionIndex but don't fire any change notifications.
@ignore
*/
- (BOOL)__setSelectionIndex:(int)theIndex
{
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:theIndex]];
}
/*
Like setSelectionIndexes but don't fire any change notifications.
@ignore
*/
- (BOOL)__setSelectionIndexes:(CPIndexSet)indexes
{
if (!indexes)
indexes = [CPIndexSet indexSet];
if (![indexes count])
{
if (_avoidsEmptySelection && [[self arrangedObjects] count])
indexes = [CPIndexSet indexSetWithIndex:0];
}
else
{
var objectsCount = [[self arrangedObjects] count];
// Remove out of bounds indexes.
[indexes removeIndexesInRange:CPMakeRange(objectsCount, [indexes lastIndex] + 1)];
// When avoiding empty selection and the deleted selection was at the bottom, select the last item.
if (![indexes count] && _avoidsEmptySelection && objectsCount)
indexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
}
if ([_selectionIndexes isEqualToIndexSet:indexes])
return NO;
_selectionIndexes = [indexes copy];
// Push back the new selection to the model for selectionIndexes if we have one.
// There won't be an infinite loop because of the equality check above.
[[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
return YES;
}
- (CPArray)selectedObjects
{
var objects = [[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]];
return [_CPObservableArray arrayWithArray:(objects || [])];
}
- (BOOL)setSelectedObjects:(CPArray)objects
{
[self willChangeValueForKey:@"selectionIndexes"];
[self _selectionWillChange];
[self __setSelectedObjects:objects];
[self didChangeValueForKey:@"selectionIndexes"];
[self _selectionDidChange];
}
/*
Like setSelectedObjects but don't fire any change notifications.
@ignore
*/
- (BOOL)__setSelectedObjects:(CPArray)objects
{
var set = [CPIndexSet indexSet],
count = [objects count],
arrangedObjects = [self arrangedObjects];
for (var i = 0; i < count; i++)
{
var index = [arrangedObjects indexOfObject:[objects objectAtIndex:i]];
if (index !== CPNotFound)
[set addIndex:index];
}
[self __setSelectionIndexes:set];
return YES;
}
//Moving selection
- (BOOL)canSelectPrevious
{
return [[self selectionIndexes] firstIndex] > 0
}
- (void)selectPrevious:(id)sender
{
var index = [[self selectionIndexes] firstIndex] - 1;
if (index >= 0)
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
}
- (BOOL)canSelectNext
{
return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] - 1;
}
- (void)selectNext:(id)sender
{
var index = [[self selectionIndexes] firstIndex] + 1;
if (index < [[self arrangedObjects] count])
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
}
//Add/Remove
- (void)addObject:(id)object
{
if (![self canAdd])
return;
if (_clearsFilterPredicateOnInsertion)
[self willChangeValueForKey:@"filterPredicate"];
[self willChangeValueForKey:@"content"];
[_contentObject addObject:object];
if (_clearsFilterPredicateOnInsertion)
[self __setFilterPredicate:nil];
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
{
var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors];
// selectionIndexes change notification will be fired as a result of the
// content change. Don't fire manually.
if (_selectsInsertedObjects)
[self __setSelectionIndex:pos];
else
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:1];
}
else
[self _rearrangeObjects];
[self didChangeValueForKey:@"content"];
if (_clearsFilterPredicateOnInsertion)
[self didChangeValueForKey:@"filterPredicate"];
}
- (void)insertObject:(id)anObject atArrangedObjectIndex:(int)anIndex
{
if (![self canAdd])
return;
if (_clearsFilterPredicateOnInsertion)
[self willChangeValueForKey:@"filterPredicate"];
[self willChangeValueForKey:@"content"];
[_contentObject insertObject:anObject atIndex:anIndex];
if (_clearsFilterPredicateOnInsertion)
[self __setFilterPredicate:nil];
[[self arrangedObjects] insertObject:anObject atIndex:anIndex];
// selectionIndexes change notification will be fired as a result of the
// content change. Don't fire manually.
if ([self selectsInsertedObjects])
[self __setSelectionIndex:anIndex];
else
[[self selectionIndexes] shiftIndexesStartingAtIndex:anIndex by:1];
if ([self avoidsEmptySelection] && [[self selectionIndexes] count] <= 0 && [_contentObject count] > 0)
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:0]];
[self didChangeValueForKey:@"content"];
if (_clearsFilterPredicateOnInsertion)
[self didChangeValueForKey:@"filterPredicate"];
}
- (void)removeObject:(id)object
{
if (![self canRemove])
return;
[self willChangeValueForKey:@"content"];
[_contentObject removeObject:object];
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
{
// selectionIndexes change notification will be fired as a result of the
// content change. Don't fire manually.
var pos = [_arrangedObjects indexOfObject:object];
[_arrangedObjects removeObjectAtIndex:pos];
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1];
}
[self didChangeValueForKey:@"content"];
}
- (void)add:(id)sender
{
if (![self canAdd])
return;
[self insert:sender];
}
- (void)insert:(id)sender
{
if (![self canInsert])
return;
var newObject = [self automaticallyPreparesContent] ? [self newObject] : [self _defaultNewObject];
[self addObject:newObject];
}
- (void)remove:(id)sender
{
[self removeObjects:[[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]]];
}
- (void)removeObjectsAtArrangedObjectIndexes:(CPIndexSet)indexes
{
[self _removeObjects:[[self arrangedObjects] objectsAtIndexes:indexes]];
}
- (void)addObjects:(CPArray)objects
{
if (![self canAdd])
return;
var contentArray = [self contentArray],
count = [objects count];
for (var i = 0; i < count; i++)
[contentArray addObject:[objects objectAtIndex:i]];
[self setContent:contentArray];
}
- (void)removeObjects:(CPArray)objects
{
if (![self canRemove])
return;
[self _removeObjects:objects];
}
- (void)_removeObjects:(CPArray)objects
{
[self willChangeValueForKey:@"content"];
[_contentObject removeObjectsInArray:objects];
var arrangedObjects = [self arrangedObjects],
position = [arrangedObjects indexOfObject:[objects objectAtIndex:0]];
[arrangedObjects removeObjectsInArray:objects];
var objectsCount = [arrangedObjects count],
selectionIndexes = [CPIndexSet indexSet];
if ([self preservesSelection] || [self avoidsEmptySelection])
{
selectionIndexes = [CPIndexSet indexSetWithIndex:position];
// Remove the selection if there are no objects
if (objectsCount <= 0)
selectionIndexes = [CPIndexSet indexSet];
// Shift selection to last object if position is out of bounds
else if (position >= objectsCount)
selectionIndexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
}
_selectionIndexes = selectionIndexes;
[self didChangeValueForKey:@"content"];
}
- (BOOL)canInsert
{
return [self isEditable];
}
@end
@implementation CPArrayController (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:coder];
if (self)
{
_avoidsEmptySelection = [coder decodeBoolForKey:@"CPArrayControllerAvoidsEmptySelection"];
_clearsFilterPredicateOnInsertion = [coder decodeBoolForKey:@"CPClearsFilterPredicateOnInsertion"];
_filterRestrictsInsertion = [coder decodeBoolForKey:@"CPArrayControllerFilterRestrictsInsertion"];
_preservesSelection = [coder decodeBoolForKey:@"CPArrayControllerPreservesSelection"];
_selectsInsertedObjects = [coder decodeBoolForKey:@"CPArrayControllerSelectsInsertedObjects"];
_alwaysUsesMultipleValuesMarker = [coder decodeBoolForKey:@"CPArrayControllerAlwaysUsesMultipleValuesMarker"];
if ([self automaticallyPreparesContent])
[self prepareContent];
else
[self _setContentArray:[]];
}
return self;
}
- (void)awakeFromCib
{
[self _selectionWillChange];
[self _selectionDidChange];
}
@end
+11 -10
View File
@@ -4,7 +4,7 @@
* Created by Ross Boucher.
* Copyright 2009, 280 North, Inc.
*
* Adapted from Kevin Wojniak, portions Copyright 2009 Kevin Wojniak.
* Adapted from Kevin Wojniak, portions Copyright 2009 Kevin Wojniak.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,26 +20,27 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright 2009 280 North, Inc.
*/
@import <AppKit/CPGraphicsContext.j>
@import <Foundation/CPObject.j>
@import "CPGraphicsContext.j"
// Class defaults
var DefaultLineWidth = 1.0;
/*!
/*!
@ingroup appkit
@class CPBezierPath
A CPBezierPath allows you to create paths for drawing to the screen using a simpler API than CoreGraphics.
Paths can form any shape, including regular polgyons like squares and triangles; circles, arcs; or complex
line segments.
line segments.
A path can be stroked and filled using the relevant method. The currently active fill and stroke color will
be used, which can be set by calling setFill: and setStroke: on any CPColor object (or set: for both).
*/
@@ -64,9 +65,9 @@ var DefaultLineWidth = 1.0;
+ (CPBezierPath)bezierPathWithOvalInRect:(CGRect)rect
{
var path = [self bezierPath];
[path appendBezierPathWithOvalInRect:rect];
return path;
}
@@ -76,9 +77,9 @@ var DefaultLineWidth = 1.0;
+ (CPBezierPath)bezierPathWithRect:(CGRect)rect
{
var path = [self bezierPath];
[path appendBezierPathWithRect:rect];
return path;
}
+176 -52
View File
@@ -19,25 +19,33 @@
* 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 "CPView.j"
// CPBoxType
CPBoxPrimary = 0;
CPBoxSecondary = 1;
CPBoxSeperator = 2;
CPBoxOldStyle = 3;
CPBoxCustom = 4;
// CPBorderType
CPNoBorder = 0;
CPLineBorder = 1;
CPLineBorder = 1;
CPBezelBorder = 2;
CPGrooveBorder = 3;
@implementation CPBox : CPView
{
CPBoxType _boxType;
CPBorderType _borderType;
CPColor _borderColor;
CPColor _fillColor;
float _cornerRadius;
float _borderWidth;
CPSize _contentMargin;
CPView _contentView;
}
@@ -50,18 +58,19 @@ CPGrooveBorder = 3;
[box setFrameFromContentFrame:[aView frame]];
[enclosingView replaceSubview:aView with:box];
[box setContentView:aView];
return box;
}
- (id)initWithFrame:(CPRect)frameRect
{
self = [super initWithFrame:frameRect];
if (self)
{
_borderType = CPBezelBorder;
_fillColor = [CPColor clearColor];
_borderColor = [CPColor blackColor];
@@ -69,7 +78,9 @@ CPGrooveBorder = 3;
_contentMargin = CGSizeMake(0.0, 0.0);
_contentView = [[CPView alloc] initWithFrame:[self bounds]];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[self setAutoresizesSubviews:YES];
[self addSubview:_contentView];
}
@@ -88,9 +99,26 @@ CPGrooveBorder = 3;
return _borderType;
}
- (void)setBorderType:(CPBorderType)value
- (void)setBorderType:(CPBorderType)aBorderType
{
_borderType = value;
if (_borderType === aBorderType)
return;
_borderType = aBorderType;
[self setNeedsDisplay:YES];
}
- (CPBoxType)boxType
{
return _boxType;
}
- (void)setBoxType:(CPBoxType)aBoxType
{
if (_boxType === aBoxType)
return;
_boxType = aBoxType;
[self setNeedsDisplay:YES];
}
@@ -161,9 +189,10 @@ CPGrooveBorder = 3;
return;
[aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)];
[aView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[self replaceSubview:_contentView with:aView];
_contentView = aView;
_contentView = aView;
}
- (CPSize)contentViewMargins
@@ -173,9 +202,9 @@ CPGrooveBorder = 3;
- (void)setContentViewMargins:(CPSize)size
{
if(size.width < 0 || size.height < 0)
if (size.width < 0 || size.height < 0)
[CPException raise:CPGenericException reason:@"Margins must be positive"];
_contentMargin = CGSizeMakeCopy(size);
[self setNeedsDisplay:YES];
}
@@ -189,56 +218,151 @@ CPGrooveBorder = 3;
- (void)sizeToFit
{
var contentFrame = [_contentView frame];
[self setFrameSize:CGSizeMake(contentFrame.size.width + _contentMargin.width * 2,
[self setFrameSize:CGSizeMake(contentFrame.size.width + _contentMargin.width * 2,
contentFrame.size.height + _contentMargin.height * 2)];
[_contentView setFrameOrigin:CGPointMake(_contentMargin.width, _contentMargin.height)];
}
- (void)drawRect:(CPRect)rect
{
var bounds = [self bounds],
aContext = [[CPGraphicsContext currentContext] graphicsPort],
border2 = _borderWidth/2,
if (_borderType === CPNoBorder)
return;
strokeRect = CGRectMake(bounds.origin.x + border2,
bounds.origin.y + border2,
bounds.size.width - _borderWidth,
bounds.size.height - _borderWidth),
fillRect = CGRectMake(bounds.origin.x + border2,
bounds.origin.y + border2,
bounds.size.width - _borderWidth,
bounds.size.height - _borderWidth);
var bounds = [self bounds];
CGContextSetFillColor(aContext, [self fillColor]);
CGContextSetStrokeColor(aContext, [self borderColor]);
CGContextSetLineWidth(aContext, _borderWidth);
switch(_borderType)
switch (_boxType)
{
case CPLineBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
CGContextStrokeRoundedRectangleInRect(aContext, strokeRect, _cornerRadius, YES, YES, YES, YES);
break;
case CPBoxSeperator:
// NSBox does not include a horitontal flag for the seperator type. We have to determine
// the type of seperator to draw by the width and height of the frame.
if (CGRectGetWidth(bounds) === 5.0)
return [self _drawVerticalSeperatorInRect:bounds];
else if (CGRectGetHeight(bounds) === 5.0)
return [self _drawHorizontalSeperatorInRect:bounds];
case CPBezelBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
CGContextSetStrokeColor(aContext, [CPColor colorWithWhite:190.0/255.0 alpha:1.0]);
CGContextBeginPath(aContext);
CGContextMoveToPoint(aContext, strokeRect.origin.x, strokeRect.origin.y);
CGContextAddLineToPoint(aContext, CGRectGetMinX(strokeRect), CGRectGetMaxY(strokeRect)),
CGContextAddLineToPoint(aContext, CGRectGetMaxX(strokeRect), CGRectGetMaxY(strokeRect)),
CGContextAddLineToPoint(aContext, CGRectGetMaxX(strokeRect), CGRectGetMinY(strokeRect)),
CGContextStrokePath(aContext);
CGContextSetStrokeColor(aContext, [CPColor colorWithWhite:142.0/255.0 alpha:1.0]);
CGContextBeginPath(aContext);
CGContextMoveToPoint(aContext, bounds.origin.x, strokeRect.origin.y);
CGContextAddLineToPoint(aContext, CGRectGetMaxX(bounds), CGRectGetMinY(strokeRect));
CGContextStrokePath(aContext);
break;
break;
}
default: break;
switch (_borderType)
{
case CPBezelBorder:
[self _drawBezelBorderInRect:bounds];
break;
default:
case CPLineBorder:
[self _drawLineBorderInRect:bounds];
break;
}
}
- (void)_drawHorizontalSeperatorInRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSetStrokeColor(context, [self borderColor]);
CGContextSetLineWidth(context, 1.0);
CGContextMoveToPoint(context, CGRectGetMinX(aRect), CGRectGetMinY(aRect));
CGContextAddLineToPoint(context, CGRectGetWidth(aRect), CGRectGetMinY(aRect));
CGContextStrokePath(context);
}
- (void)_drawVerticalSeperatorInRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSetStrokeColor(context, [self borderColor]);
CGContextSetLineWidth(context, 1.0);
CGContextMoveToPoint(context, CGRectGetMinX(aRect), CGRectGetMinY(aRect));
CGContextAddLineToPoint(context, CGRectGetMinX(aRect), CGRectGetHeight(aRect));
CGContextStrokePath(context);
}
- (void)_drawBezelBorderInRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
sides = [CPMinYEdge, CPMaxXEdge, CPMaxYEdge, CPMinXEdge],
sideGray = 190.0 / 255.0,
grays = [142.0 / 255.0, sideGray, sideGray, sideGray],
borderWidth = _borderWidth;
while (borderWidth--)
aRect = CPDrawTiledRects(aRect, aRect, sides, grays);
CGContextSetFillColor(context, [self fillColor]);
CGContextFillRect(context, aRect);
}
- (void)_drawLineBorderInRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort];
aRect = CGRectInset(aRect, _borderWidth / 2.0, _borderWidth / 2.0);
CGContextSetFillColor(context, [self fillColor]);
CGContextSetStrokeColor(context, [self borderColor]);
CGContextSetLineWidth(context, _borderWidth);
CGContextFillRoundedRectangleInRect(context, aRect, _cornerRadius, YES, YES, YES, YES);
CGContextStrokeRoundedRectangleInRect(context, aRect, _cornerRadius, YES, YES, YES, YES);
}
@end
var CPBoxTypeKey = @"CPBoxTypeKey",
CPBoxBorderTypeKey = @"CPBoxBorderTypeKey",
CPBoxBorderColorKey = @"CPBoxBorderColorKey",
CPBoxFillColorKey = @"CPBoxFillColorKey",
CPBoxCornerRadiusKey = @"CPBoxCornerRadiusKey",
CPBoxBorderWidthKey = @"CPBoxBorderWidthKey",
CPBoxContentMarginKey = @"CPBoxContentMarginKey";
@implementation CPBox (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
_boxType = [aCoder decodeIntForKey:CPBoxTypeKey];
_borderType = [aCoder decodeIntForKey:CPBoxBorderTypeKey];
_borderColor = [aCoder decodeObjectForKey:CPBoxBorderColorKey];
_fillColor = [aCoder decodeObjectForKey:CPBoxFillColorKey];
_cornerRadius = [aCoder decodeFloatForKey:CPBoxCornerRadiusKey];
_borderWidth = [aCoder decodeFloatForKey:CPBoxBorderWidthKey];
_contentMargin = [aCoder decodeSizeForKey:CPBoxContentMarginKey];
_contentView = [self subviews][0];
[self setAutoresizesSubviews:YES];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeInt:_boxType forKey:CPBoxTypeKey];
[aCoder encodeInt:_borderType forKey:CPBoxBorderTypeKey];
[aCoder encodeObject:_borderColor forKey:CPBoxBorderColorKey];
[aCoder encodeObject:_fillColor forKey:CPBoxFillColorKey];
[aCoder encodeFloat:_cornerRadius forKey:CPBoxCornerRadiusKey];
[aCoder encodeFloat:_borderWidth forKey:CPBoxBorderWidthKey];
[aCoder encodeSize:_contentMargin forKey:CPBoxContentMarginKey];
}
@end
+955
View File
@@ -0,0 +1,955 @@
/*
* CPBrowser.j
* AppKit
*
* Created by Ross Boucher.
* Copyright 2010, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPIndexSet.j>
@import "CPControl.j"
@import "CPImage.j"
@import "CPTableView.j"
@import "CPTextField.j"
@import "CPScrollView.j"
/*!
@ingroup appkit
@class CPBrowser
*/
@implementation CPBrowser : CPControl
{
id _delegate;
CPString _pathSeparator;
CPView _contentView;
CPScrollView _horizontalScrollView;
CPView _prototypeView;
CPArray _tableViews;
CPArray _tableDelegates;
id _rootItem;
BOOL _delegateSupportsImages;
SEL _doubleAction @accessors(property=doubleAction);
BOOL _allowsMultipleSelection;
BOOL _allowsEmptySelection;
Class _tableViewClass @accessors(property=tableViewClass);
float _rowHeight;
float _imageWidth;
float _leafWidth;
float _minColumnWidth;
float _defaultColumnWidth @accessors(property=defaultColumnWidth);
CPArray _columnWidths;
}
+ (CPImage)branchImage
{
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
pathForResource:"browser-leaf.png"]
size:CGSizeMake(9,9)];
}
+ (CPImage)highlightedBranchImage
{
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
pathForResource:"browser-leaf-highlighted.png"]
size:CGSizeMake(9,9)];
}
- (id)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
_rowHeight = 23.0;
_defaultColumnWidth = 140.0;
_minColumnWidth = 80.0;
_imageWidth = 23.0;
_leafWidth = 13.0;
_columnWidths = [];
_pathSeparator = "/";
_tableViews = [];
_tableDelegates = [];
_allowsMultipleSelection = YES;
_allowsEmptySelection = YES;
_tableViewClass = [_CPBrowserTableView class];
_prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelectedDataView];
[_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail];
_horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
[_horizontalScrollView setHasVerticalScroller:NO];
[_horizontalScrollView setAutohidesScrollers:YES];
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
_contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))];
[_contentView setAutoresizingMask:CPViewHeightSizable];
[_horizontalScrollView setDocumentView:_contentView];
[self addSubview:_horizontalScrollView];
}
return self;
}
- (void)setPrototypeView:(CPView)aPrototypeView
{
_prototypeView = [CPKeyedUnarchiver unarchiveObjectWithData:
[CPKeyedArchiver archivedDataWithRootObject:aPrototypeView]];
}
- (CPView)prototypeView
{
return [CPKeyedUnarchiver unarchiveObjectWithData:
[CPKeyedArchiver archivedDataWithRootObject:_prototypeView]];
}
- (void)setDelegate:(id)anObject
{
_delegate = anObject;
_delegateSupportsImages = [_delegate respondsToSelector:@selector(browser:imageValueForItem:)];
[self loadColumnZero];
}
- (id)delegate
{
return _delegate;
}
- (CPTableView)tableViewInColumn:(unsigned)index
{
return _tableViews[index];
}
- (unsigned)columnOfTableView:(CPTableView)aTableView
{
return [_tableViews indexOfObject:aTableView];
}
- (void)loadColumnZero
{
if ([_delegate respondsToSelector:@selector(rootItemForBrowser:)])
_rootItem = [_delegate rootItemForBrowser:self];
else
_rootItem = nil;
[self setLastColumn:-1];
[self addColumn];
}
- (void)setLastColumn:(int)columnIndex
{
if (columnIndex >= _tableViews.length)
return;
var oldValue = _tableViews.length - 1,
indexPlusOne = columnIndex + 1; // unloads all later columns.
[[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
makeObjectsPerformSelector:@selector(removeFromSuperview)];
_tableViews = _tableViews.slice(0, indexPlusOne);
_tableDelegates = _tableDelegates.slice(0, indexPlusOne);
if ([_delegate respondsToSelector:@selector(browser:didChangeLastColumn:toColumn:)])
[_delegate browser:self didChangeLastColumn:oldValue toColumn:columnIndex];
[self tile];
}
- (int)lastColumn
{
return _tableViews.length - 1;
}
- (void)addColumn
{
var lastIndex = [self lastColumn],
lastColumn = _tableViews[lastIndex],
selectionIndexes = [lastColumn selectedRowIndexes];
if (lastIndex >= 0 && [selectionIndexes count] > 1)
[CPException raise:CPInvalidArgumentException
reason:"Can't add column, column "+lastIndex+" has invalid selection."];
var index = lastIndex + 1,
item = index === 0 ? _rootItem : [_tableDelegates[lastIndex] childAtIndex:[selectionIndexes firstIndex]];
if (index > 0 && item && [self isLeafItem:item])
return;
var table = [[_tableViewClass alloc] initWithFrame:CGRectMakeZero() browser:self];
[table setHeaderView:nil];
[table setCornerView:nil];
[table setAllowsMultipleSelection:_allowsMultipleSelection];
[table setAllowsEmptySelection:_allowsEmptySelection];
[table registerForDraggedTypes:[self registeredDraggedTypes]];
[self _addTableColumnsToTableView:table forColumnIndex:index];
var delegate = [[_CPBrowserTableDelegate alloc] init];
[delegate _setDelegate:_delegate];
[delegate _setBrowser:self];
[delegate _setIndex:index];
[delegate _setItem:item];
_tableViews[index] = table;
_tableDelegates[index] = delegate;
[table setDelegate:delegate];
[table setDataSource:delegate];
[table setTarget:delegate];
[table setAction:@selector(_tableViewClicked:)];
[table setDoubleAction:@selector(_tableViewDoubleClicked:)];
[table setDraggingDestinationFeedbackStyle:CPTableViewDraggingDestinationFeedbackStyleRegular];
var scrollView = [[_CPBrowserScrollView alloc] initWithFrame:CGRectMakeZero()];
[scrollView _setBrowser:self];
[scrollView setDocumentView:table];
[scrollView setHasHorizontalScroller:NO];
[scrollView setAutoresizingMask:CPViewHeightSizable];
[_contentView addSubview:scrollView];
[self tile];
[self scrollColumnToVisible:index];
}
- (void)_addTableColumnsToTableView:(CPTableView)aTableView forColumnIndex:(unsigned)index
{
if (_delegateSupportsImages)
{
var column = [[CPTableColumn alloc] initWithIdentifier:@"Image"],
view = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
[view setImageScaling:CPScaleProportionally];
[column setDataView:view];
[column setResizingMask:CPTableColumnNoResizing];
[aTableView addTableColumn:column];
}
var column = [[CPTableColumn alloc] initWithIdentifier:@"Content"];
[column setDataView:_prototypeView];
[column setResizingMask:CPTableColumnNoResizing];
[aTableView addTableColumn:column];
var column = [[CPTableColumn alloc] initWithIdentifier:@"Leaf"],
view = [[_CPBrowserLeafView alloc] initWithFrame:CGRectMakeZero()];
[view setBranchImage:[[self class] branchImage]];
[view setHighlightedBranchImage:[[self class] highlightedBranchImage]];
[column setDataView:view];
[column setResizingMask:CPTableColumnNoResizing];
[aTableView addTableColumn:column];
}
- (void)reloadColumn:(int)column
{
[[self tableViewInColumn:column] reloadData];
}
- (void)tile
{
var xOrigin = 0,
scrollerWidth = [CPScroller scrollerWidth],
height = CGRectGetHeight([_contentView bounds]);
for (var i = 0, count = _tableViews.length; i < count; i++)
{
var tableView = _tableViews[i],
scrollView = [tableView enclosingScrollView],
width = [self widthOfColumn:i],
tableHeight = CGRectGetHeight([tableView bounds]);
[[tableView tableColumnWithIdentifier:"Image"] setWidth:_imageWidth];
[[tableView tableColumnWithIdentifier:"Content"] setWidth:width - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - scrollerWidth - scrollerWidth];
[[tableView tableColumnWithIdentifier:"Leaf"] setWidth:_leafWidth];
[tableView setRowHeight:_rowHeight];
[tableView setFrameSize:CGSizeMake(width - scrollerWidth, tableHeight)];
[scrollView setFrameOrigin:CGPointMake(xOrigin, 0)];
[scrollView setFrameSize:CGSizeMake(width, height)];
xOrigin += width;
}
[_contentView setFrameSize:CGSizeMake(xOrigin, height)];
}
- (unsigned)rowAtPoint:(CGPoint)aPoint
{
var column = [self columnAtPoint:aPoint];
if (column === -1)
return -1;
var tableView = _tableViews[column];
return [tableView rowAtPoint:[tableView convertPoint:aPoint fromView:self]];
}
- (unsigned)columnAtPoint:(CGPoint)aPoint
{
var adjustedPoint = [_contentView convertPoint:aPoint fromView:self];
for (var i = 0, count = _tableViews.length; i < count; i++)
{
var frame = [[_tableViews[i] enclosingScrollView] frame];
if (CGRectContainsPoint(frame, adjustedPoint))
return i;
}
return -1;
}
- (CGRect)rectOfRow:(unsigned)aRow inColumn:(unsigned)aColumn
{
var tableView = _tableViews[aColumn],
rect = [tableView rectOfRow:aRow];
rect.origin = [self convertPoint:rect.origin fromView:tableView];
return rect;
}
// ITEMS
- (id)itemAtRow:(int)row inColumn:(int)column
{
return [_tableDelegates[column] childAtIndex:row];
}
- (BOOL)isLeafItem:(id)item
{
return [_delegate respondsToSelector:@selector(browser:isLeafItem:)] && [_delegate browser:self isLeafItem:item];
}
- (id)parentForItemsInColumn:(int)column
{
return [_tableDelegates[column] _item];
}
- (CPSet)selectedItems
{
var selectedColumn = [self selectedColumn],
selectedIndexes = [self selectedRowIndexesInColumn:selectedColumn],
set = [CPSet set],
index = [selectedIndexes firstIndex];
while (index !== CPNotFound)
{
[set addObject:[self itemAtRow:index inColumn:selectedColumn]];
index = [selectedIndexes indexGreaterThanIndex:index];
}
return set;
}
- (id)selectedItem
{
var selectedColumn = [self selectedColumn],
selectedRow = [self selectedRowInColumn:selectedColumn];
return [self itemAtRow:selectedRow inColumn:selectedColumn];
}
// CLICK EVENTS
- (void)trackMouse:(CPEvent)anEvent
{
}
- (void)_column:(unsigned)columnIndex clickedRow:(unsigned)rowIndex
{
[self setLastColumn:columnIndex];
if (rowIndex >= 0)
[self addColumn];
[self doClick:self];
}
- (void)sendAction
{
[self sendAction:_action to:_target];
}
- (void)doClick:(id)sender
{
[self sendAction:_action to:_target];
}
- (void)doDoubleClick:(id)sender
{
[self sendAction:_doubleAction to:_target];
}
- (void)keyDown:(CPEvent)anEvent
{
var column = [self selectedColumn];
if (column === -1)
return;
[_tableViews[column] keyDown:anEvent];
}
// SIZING
- (float)columnContentWidthForColumnWidth:(float)aWidth
{
return aWidth - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - [CPScroller scrollerWidth];
}
- (float)columnWidthForColumnContentWidth:(float)aWidth
{
return aWidth + (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) + [CPScroller scrollerWidth];
}
- (void)setImageWidth:(float)aWidth
{
_imageWidth = aWidth;
[self tile];
}
- (float)imageWidth
{
return _imageWidth;
}
- (void)setMinColumnWidth:(float)minWidth
{
_minColumnWidth = minWidth;
[self tile];
}
- (float)minColumnWidth
{
return _minColumnWidth;
}
- (void)setWidth:(float)aWidth ofColumn:(unsigned)column
{
_columnWidths[column] = aWidth;
if ([_delegate respondsToSelector:@selector(browser:didResizeColumn:)])
[_delegate browser:self didResizeColumn:column];
[self tile];
}
- (float)widthOfColumn:(unsigned)column
{
var width = _columnWidths[column];
if (width == null)
width = _defaultColumnWidth;
return MAX([CPScroller scrollerWidth], MAX(_minColumnWidth, width));
}
- (void)setRowHeight:(float)aHeight
{
_rowHeight = aHeight;
}
- (float)rowHeight
{
return _rowHeight;
}
// SCROLLERS
- (void)scrollColumnToVisible:(unsigned)columnIndex
{
[_contentView scrollRectToVisible:[[[self tableViewInColumn:columnIndex] enclosingScrollView] frame]];
}
- (void)scrollRowToVisible:(unsigned)rowIndex inColumn:(unsigned)columnIndex
{
[self scrollColumnToVisible:columnIndex];
[[self tableViewInColumn:columnIndex] scrollRowToVisible:rowIndex];
}
- (BOOL)autohidesScroller
{
return [_horizontalScrollView autohidesScrollers];
}
- (void)setAutohidesScroller:(BOOL)shouldHide
{
[_horizontalScrollView setAutohidesScrollers:shouldHide];
}
// SELECTION
- (unsigned)selectedRowInColumn:(unsigned)columnIndex
{
if (columnIndex > [self lastColumn] || columnIndex < 0)
return -1;
return [_tableViews[columnIndex] selectedRow];
}
- (unsigned)selectedColumn
{
var column = [self lastColumn],
row = [self selectedRowInColumn:column];
if (row >= 0)
return column;
else
return column - 1;
}
- (void)selectRow:(unsigned)row inColumn:(unsigned)column
{
var selectedIndexes = row === -1 ? [CPIndexSet indexSet] : [CPIndexSet indexSetWithIndex:row];
[self selectRowIndexes:selectedIndexes inColumn:column];
}
- (BOOL)allowsMultipleSelection
{
return _allowsMultipleSelection;
}
- (void)setAllowsMultipleSelection:(BOOL)shouldAllow
{
if (_allowsMultipleSelection === shouldAllow)
return;
_allowsMultipleSelection = shouldAllow;
[_tableViews makeObjectsPerformSelector:@selector(setAllowsMultipleSelection:) withObject:shouldAllow];
}
- (BOOL)allowsEmptySelection
{
return _allowsEmptySelection;
}
- (void)setAllowsEmptySelection:(BOOL)shouldAllow
{
if (_allowsEmptySelection === shouldAllow)
return;
_allowsEmptySelection = shouldAllow;
[_tableViews makeObjectsPerformSelector:@selector(setAllowsEmptySelection:) withObject:shouldAllow];
}
- (CPIndexSet)selectedRowIndexesInColumn:(unsigned)column
{
if (column < 0 || column > [self lastColumn] +1)
return [CPIndexSet indexSet];
return [[self tableViewInColumn:column] selectedRowIndexes];
}
- (void)selectRowIndexes:(CPIndexSet)indexSet inColumn:(unsigned)column
{
if (column < 0 || column > [self lastColumn] + 1)
return;
if ([_delegate respondsToSelector:@selector(browser:selectionIndexesForProposedSelection:inColumn:)])
indexSet = [_delegate browser:self selectionIndexesForProposedSelection:indexSet inColumn:column];
if ([_delegate respondsToSelector:@selector(browser:shouldSelectRowIndexes:inColumn:)] &&
![_delegate browser:self shouldSelectRowIndexes:indexSet inColumn:column])
return;
if ([_delegate respondsToSelector:@selector(browserSelectionIsChanging:)])
[_delegate browserSelectionIsChanging:self];
if (column > [self lastColumn])
[self addColumn];
[self setLastColumn:column];
[[self tableViewInColumn:column] selectRowIndexes:indexSet byExtendingSelection:NO];
[self scrollColumnToVisible:column];
if ([_delegate respondsToSelector:@selector(browserSelectionDidChange:)])
[_delegate browserSelectionDidChange:self];
}
- (void)setBackgroundColor:(CPColor)aColor
{
[super setBackgroundColor:aColor];
[_contentView setBackgroundColor:aColor];
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
// DRAG AND DROP
- (void)registerForDraggedTypes:(CPArray)types
{
[super registerForDraggedTypes:types];
[_tableViews makeObjectsPerformSelector:@selector(registerForDraggedTypes:) withObject:types];
}
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)columnIndex withEvent:(CPEvent)dragEvent
{
if ([_delegate respondsToSelector:@selector(browser:canDragRowsWithIndexes:inColumn:withEvent:)])
return [_delegate browser:self canDragRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent];
return YES;
}
- (CPImage)draggingImageForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
{
if ([_delegate respondsToSelector:@selector(browser:draggingImageForRowsWithIndexes:inColumn:withEvent:offset:)])
return [_delegate browser:self draggingImageForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
return nil;
}
- (CPView)draggingViewForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
{
if ([_delegate respondsToSelector:@selector(browser:draggingViewForRowsWithIndexes:inColumn:withEvent:offset:)])
return [_delegate browser:self draggingViewForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
return nil;
}
@end
var _CPBrowserResizeControlBackgroundImage = nil;
@implementation _CPBrowserResizeControl : CPView
{
CGPoint _mouseDownX;
CPBrowser _browser;
unsigned _index;
unsigned _width;
}
+ (CPImage)backgroundImage
{
if (!_CPBrowserResizeControlBackgroundImage)
{
var path = [[CPBundle bundleForClass:[self class]] pathForResource:"browser-resize-control.png"];
_CPBrowserResizeControlBackgroundImage = [[CPImage alloc] initWithContentsOfFile:path
size:CGSizeMake(15, 14)];
}
return _CPBrowserResizeControlBackgroundImage;
}
- (id)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
[self setBackgroundColor:[CPColor colorWithPatternImage:[[self class] backgroundImage]]];
return self;
}
- (void)mouseDown:(CPEvent)anEvent
{
_mouseDownX = [anEvent locationInWindow].x;
_browser = [[self superview] _browser];
_index = [_browser columnOfTableView:[[self superview] documentView]];
_width = [_browser widthOfColumn:_index];
}
- (void)mouseDragged:(CPEvent)anEvent
{
var deltaX = [anEvent locationInWindow].x - _mouseDownX;
[_browser setWidth:_width + deltaX ofColumn:_index];
}
- (void)mouseUp:(CPEvent)anEvent
{
}
@end
@implementation _CPBrowserScrollView : CPScrollView
{
_CPBrowserResizeControl _resizeControl;
CPBrowser _browser @accessors;
}
- (void)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
_resizeControl = [[_CPBrowserResizeControl alloc] initWithFrame:CGRectMakeZero()];
[self addSubview:_resizeControl];
}
return self;
}
- (void)reflectScrolledClipView:(CPClipView)aClipView
{
[super reflectScrolledClipView:aClipView];
var frame = [_verticalScroller frame];
frame.size.height = CGRectGetHeight([self bounds]) - 14.0 - frame.origin.y;
[_verticalScroller setFrameSize:frame.size];
var resizeFrame = CGRectMake(CGRectGetMinX(frame), CGRectGetMaxY(frame), [CPScroller scrollerWidth], 14.0);
[_resizeControl setFrame:resizeFrame];
}
@end
@implementation _CPBrowserTableView : CPTableView
{
CPBrowser _browser;
}
- (id)initWithFrame:(CGRect)aFrame browser:(CPBrowser)aBrowser
{
if (self = [super initWithFrame:aFrame])
_browser = aBrowser;
return self;
}
- (BOOL)acceptsFirstResponder
{
return NO;
}
- (void)mouseDown:(CPEvent)anEvent
{
[super mouseDown:anEvent];
[[self window] makeFirstResponder:_browser];
}
- (CPView)browserView
{
return _browser;
}
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes atPoint:(CGPoint)mouseDownPoint
{
return [_browser canDragRowsWithIndexes:rowIndexes inColumn:[_browser columnOfTableView:self] withEvent:[CPApp currentEvent]];
}
- (CPImage)dragImageForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CPPointPointer)dragImageOffset
{
return [_browser draggingImageForRowsWithIndexes:dragRows inColumn:[_browser columnOfTableView:self] withEvent:dragEvent offset:dragImageOffset] ||
[super dragImageForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragImageOffset];
}
- (CPView)dragViewForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CPPoint)dragViewOffset
{
var count = theTableColumns.length;
while (count--)
{
if ([theTableColumns[count] identifier] === "Leaf")
[theTableColumns removeObject:theTableColumns[count]];
}
return [_browser draggingViewForRowsWithIndexes:dragRows inColumn:[_browser columnOfTableView:self] withEvent:dragEvent offset:dragViewOffset] ||
[super dragViewForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragViewOffset];
}
- (void)moveUp:(id)sender
{
[super moveUp:sender];
[_browser selectRow:[self selectedRow] inColumn:[_browser selectedColumn]];
}
- (void)moveDown:(id)sender
{
[super moveDown:sender];
[_browser selectRow:[self selectedRow] inColumn:[_browser selectedColumn]];
}
- (void)moveLeft:(id)sender
{
var previousColumn = [_browser selectedColumn] - 1,
selectedRow = [_browser selectedRowInColumn:previousColumn];
[_browser selectRow:selectedRow inColumn:previousColumn];
}
- (void)moveRight:(id)sender
{
[_browser selectRow:0 inColumn:[_browser selectedColumn] + 1];
}
@end
@import <Foundation/CPObject.j>
@implementation _CPBrowserTableDelegate : CPObject
{
CPBrowser _browser @accessors;
unsigned _index @accessors;
id _delegate @accessors;
id _item @accessors;
}
- (unsigned)numberOfRowsInTableView:(CPTableView)aTableView
{
return [_delegate browser:_browser numberOfChildrenOfItem:_item];
}
- (void)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)column row:(unsigned)row
{
if ([column identifier] === "Image")
return [_delegate browser:_browser imageValueForItem:[self childAtIndex:row]];
else if ([column identifier] === "Leaf")
return ![_browser isLeafItem:[self childAtIndex:row]];
else
return [_delegate browser:_browser objectValueForItem:[self childAtIndex:row]];
}
- (void)_tableViewDoubleClicked:(CPTableView)aTableView
{
[_browser doDoubleClick:self];
}
- (void)_tableViewClicked:(CPTableView)aTableView
{
var selectedIndexes = [aTableView selectedRowIndexes];
[_browser _column:_index clickedRow:[selectedIndexes count] === 1 ? [selectedIndexes firstIndex] : -1];
}
- (id)childAtIndex:(unsigned)index
{
return [_delegate browser:_browser child:index ofItem:_item];
}
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id)info row:(int)row dropOperation:(CPTableViewDropOperation)operation
{
if ([_delegate respondsToSelector:@selector(browser:acceptDrop:atRow:column:dropOperation:)])
return [_delegate browser:_browser acceptDrop:info atRow:row column:_index dropOperation:operation];
else
return NO;
}
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(int)row proposedDropOperation:(CPTableViewDropOperation)operation
{
if ([_delegate respondsToSelector:@selector(browser:validateDrop:proposedRow:column:dropOperation:)])
return [_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
else
return CPDragOperationNone;
}
- (BOOL)tableView:(CPTableView)aTableView writeRowsWithIndexes:(CPIndexSet)rowIndexes toPasteboard:(CPPasteboard)pboard
{
if ([_delegate respondsToSelector:@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)])
return [_delegate browser:_browser writeRowsWithIndexes:rowIndexes inColumn:_index toPasteboard:pboard];
else
return NO;
}
- (BOOL)respondsToSelector:(SEL)aSelector
{
if (aSelector === @selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:))
return [_delegate respondsToSelector:@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)];
else
return [super respondsToSelector:aSelector];
}
@end
@implementation _CPBrowserLeafView : CPView
{
BOOL _isLeaf @accessors(readonly, property=isLeaf);
CPImage _branchImage @accessors(property=branchImage);
CPImage _highlightedBranchImage @accessors(property=highlightedBranchImage);
}
- (BOOL)objectValue
{
return _isLeaf;
}
- (void)setObjectValue:(id)aValue
{
_isLeaf = !!aValue;
[self setNeedsLayout];
}
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
{
if (aName === "image-view")
return CGRectInset([self bounds], 1, 1);
return [super rectForEphemeralSubviewNamed:aName];
}
- (CPView)createEphemeralSubviewNamed:(CPString)aName
{
if (aName === "image-view")
return [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
return [super createEphemeralSubviewNamed:aName];
}
- (void)layoutSubviews
{
var imageView = [self layoutEphemeralSubviewNamed:@"image-view"
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:nil],
isHighlighted = [self themeState] & CPThemeStateSelectedDataView;
[imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil];
[imageView setImageScaling:CPScaleNone];
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeBool:_isLeaf forKey:"_CPBrowserLeafViewIsLeafKey"];
[aCoder encodeObject:_branchImage forKey:"_CPBrowserLeafViewBranchImageKey"];
[aCoder encodeObject:_highlightedBranchImage forKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
}
- (void)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_isLeaf = [aCoder decodeBoolForKey:"_CPBrowserLeafViewIsLeafKey"];
_branchImage = [aCoder decodeObjectForKey:"_CPBrowserLeafViewBranchImageKey"];
_highlightedBranchImage = [aCoder decodeObjectForKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
}
return self;
}
@end
+176 -74
View File
@@ -26,8 +26,6 @@
@import "CPControl.j"
@import "CPStringDrawing.j"
#include "CoreGraphics/CGGeometry.h"
/* @group CPBezelStyle */
@@ -74,7 +72,10 @@ CPChangeBackgroundCellMask = CPBackgroundButtonMask;
CPButtonStateMixed = CPThemeState("mixed");
/*!
CPButtonDefaultHeight = 24.0;
CPButtonImageOffset = 3.0;
/*!
@ingroup appkit
@class CPButton
@@ -85,12 +86,9 @@ CPButtonStateMixed = CPThemeState("mixed");
@implementation CPButton : CPControl
{
BOOL _allowsMixedState;
CPString _title;
CPString _alternateTitle;
CPImage _image;
CPImage _alternateImage;
CPInteger _showsStateBy;
CPInteger _highlightsBy;
@@ -99,6 +97,9 @@ CPButtonStateMixed = CPThemeState("mixed");
// NS-style Display Properties
CPBezelStyle _bezelStyle;
CPControlSize _controlSize;
CPString _keyEquivalent;
unsigned _keyEquivalentModifierMask;
}
+ (id)buttonWithTitle:(CPString)aTitle
@@ -117,21 +118,21 @@ CPButtonStateMixed = CPThemeState("mixed");
return button;
}
+ (CPString)themeClass
+ (CPString)defaultThemeClass
{
return @"button";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
return [CPDictionary dictionaryWithObjects:[[CPNull null], 0.0, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
forKeys:[@"image", @"image-offset", @"bezel-inset", @"content-inset", @"bezel-color"]];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
// Should we instead override the defaults?
@@ -139,13 +140,16 @@ CPButtonStateMixed = CPThemeState("mixed");
[self setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
[self setValue:CPScaleNone forThemeAttribute:@"image-scaling"];
_controlSize = CPRegularControlSize;
_keyEquivalent = @"";
_keyEquivalentModifierMask = 0;
// [self setBezelStyle:CPRoundRectBezelStyle];
[self setBordered:YES];
}
return self;
}
@@ -248,9 +252,9 @@ CPButtonStateMixed = CPThemeState("mixed");
{
if (_title === aTitle)
return;
_title = aTitle;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
@@ -264,7 +268,7 @@ CPButtonStateMixed = CPThemeState("mixed");
{
if (_alternateTitle === aTitle)
return;
_alternateTitle = aTitle;
[self setNeedsLayout];
@@ -278,18 +282,12 @@ CPButtonStateMixed = CPThemeState("mixed");
- (void)setImage:(CPImage)anImage
{
if (_image === anImage)
return;
_image = anImage;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
[self setValue:anImage forThemeAttribute:@"image"];
}
- (CPImage)image
{
return _image;
return [self valueForThemeAttribute:@"image" inState:CPThemeStateNormal];
}
/*!
@@ -298,13 +296,7 @@ CPButtonStateMixed = CPThemeState("mixed");
*/
- (void)setAlternateImage:(CPImage)anImage
{
if (_alternateImage === anImage)
return;
_alternateImage = anImage;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
[self setValue:anImage forThemeAttribute:@"image" inState:CPThemeStateHighlighted];
}
/*!
@@ -312,7 +304,17 @@ CPButtonStateMixed = CPThemeState("mixed");
*/
- (CPImage)alternateImage
{
return _alternateImage;
return [self valueForThemeAttribute:@"image" inState:CPThemeStateHighlighted];
}
- (void)setImageOffset:(float)theImageOffset
{
[self setValue:theImageOffset forThemeAttribute:@"image-offset"];
}
- (float)imageOffset
{
return [self valueForThemeAttribute:@"image-offset"];
}
- (void)setShowsStateBy:(CPInteger)aMask
@@ -373,13 +375,13 @@ CPButtonStateMixed = CPThemeState("mixed");
[self setShowsStateBy:CPContentsCellMask];
break;
case CPSwitchButton: [CPException raise:CPInvalidArgumentException
case CPSwitchButton: [CPException raise:CPInvalidArgumentException
reason:"The CPSwitchButton type is not supported in Cappuccino, use the CPCheckBox class instead."];
case CPRadioButton: [CPException raise:CPInvalidArgumentException
case CPRadioButton: [CPException raise:CPInvalidArgumentException
reason:"The CPRadioButton type is not supported in Cappuccino, use the CPRadio class instead."];
default: [CPException raise:CPInvalidArgumentException
default: [CPException raise:CPInvalidArgumentException
reason:"Unknown button type."];
}
@@ -395,7 +397,7 @@ CPButtonStateMixed = CPThemeState("mixed");
_imageDimsWhenDisabled = imageShouldDimWhenDisabled;
if (_imageDimsWhenDisabled)
if ([self hasThemeState:CPThemeStateDisabled])
{
[self setNeedsDisplay:YES];
[self setNeedsLayout];
@@ -410,7 +412,7 @@ CPButtonStateMixed = CPThemeState("mixed");
- (BOOL)startTrackingAt:(CGPoint)aPoint
{
[self highlight:YES];
return [super startTrackingAt:aPoint];
}
@@ -431,11 +433,12 @@ CPButtonStateMixed = CPThemeState("mixed");
if (_CGInsetIsEmpty(contentInset))
return bounds;
bounds = _CGRectMakeCopy(bounds);
bounds.origin.x += contentInset.left;
bounds.origin.y += contentInset.top;
bounds.size.width -= contentInset.left + contentInset.right;
bounds.size.height -= contentInset.top + contentInset.bottom;
return bounds;
}
@@ -449,6 +452,7 @@ CPButtonStateMixed = CPThemeState("mixed");
if (_CGInsetIsEmpty(bezelInset))
return bounds;
bounds = _CGRectMakeCopy(bounds);
bounds.origin.x += bezelInset.left;
bounds.origin.y += bezelInset.top;
bounds.size.width -= bezelInset.left + bezelInset.right;
@@ -462,8 +466,20 @@ CPButtonStateMixed = CPThemeState("mixed");
*/
- (void)sizeToFit
{
var size = [([self title] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]],
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
[self layoutSubviews];
var size,
contentView = [self ephemeralSubviewNamed:@"content-view"];
if (contentView)
{
[contentView sizeToFit];
size = [contentView frameSize];
}
else
size = [([self title] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]];
var contentInset = [self currentValueForThemeAttribute:@"content-inset"],
minSize = [self currentValueForThemeAttribute:@"min-size"],
maxSize = [self currentValueForThemeAttribute:@"max-size"];
@@ -483,10 +499,10 @@ CPButtonStateMixed = CPThemeState("mixed");
{
if (aName === "bezel-view")
return [self bezelRectForBounds:[self bounds]];
else if (aName === "content-view")
return [self contentRectForBounds:[self bounds]];
return [super rectForEphemeralSubviewNamed:aName];
}
@@ -497,13 +513,11 @@ CPButtonStateMixed = CPThemeState("mixed");
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO];
return view;
}
else
return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
return [super createEphemeralSubviewNamed:aName];
}
- (void)layoutSubviews
@@ -511,9 +525,8 @@ CPButtonStateMixed = CPThemeState("mixed");
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:@"content-view"];
if (bezelView)
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
positioned:CPWindowAbove
@@ -522,7 +535,8 @@ CPButtonStateMixed = CPThemeState("mixed");
if (contentView)
{
[contentView setText:([self hasThemeState:CPThemeStateHighlighted] && _alternateTitle) ? _alternateTitle : _title];
[contentView setImage:([self hasThemeState:CPThemeStateHighlighted] && _alternateImage) ? _alternateImage : _image];
[contentView setImage:[self currentValueForThemeAttribute:@"image"]];
[contentView setImageOffset:[self currentValueForThemeAttribute:@"image-offset"]];
[contentView setFont:[self currentValueForThemeAttribute:@"font"]];
[contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
@@ -533,17 +547,10 @@ CPButtonStateMixed = CPThemeState("mixed");
[contentView setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
[contentView setImagePosition:[self currentValueForThemeAttribute:@"image-position"]];
[contentView setImageScaling:[self currentValueForThemeAttribute:@"image-scaling"]];
[contentView setDimsImage:[self hasThemeState:CPThemeStateDisabled] && _imageDimsWhenDisabled];
}
}
- (void)setDefaultButton:(BOOL)shouldBeDefaultButton
{
if (shouldBeDefaultButton)
[self setThemeState:CPThemeStateDefault];
else
[self unsetThemeState:CPThemeStateDefault];
}
- (void)setBordered:(BOOL)shouldBeBordered
{
if (shouldBeBordered)
@@ -557,6 +564,79 @@ CPButtonStateMixed = CPThemeState("mixed");
return [self hasThemeState:CPThemeStateBordered];
}
/*!
Sets the keyboard shortcut for this button. For special keys see
CPEvent.j CP...FunctionKey and CPText.j CP...Character.
@param aString the keyboard shortcut as a string
*/
- (void)setKeyEquivalent:(CPString)aString
{
_keyEquivalent = aString || @"";
// Check if the key equivalent is the enter key
// Treat \r and \n as the same key equivalent. See issue #710.
if (aString === CPNewlineCharacter || aString === CPCarriageReturnCharacter)
[self setThemeState:CPThemeStateDefault];
else
[self unsetThemeState:CPThemeStateDefault];
}
- (void)viewWillMoveToWindow:(CPWindow)aWindow
{
var selfWindow = [self window];
if (selfWindow === aWindow || aWindow === nil)
return;
if ([selfWindow defaultButton] === self)
[selfWindow setDefaultButton:nil];
if ([self keyEquivalent] === CPNewlineCharacter || [self keyEquivalent] === CPCarriageReturnCharacter)
[aWindow setDefaultButton:self];
}
/*!
Returns the keyboard shortcut for this button.
*/
- (CPString)keyEquivalent
{
return _keyEquivalent;
}
/*!
Returns the mask used with this button's key equivalent.
*/
- (void)setKeyEquivalentModifierMask:(unsigned)aMask
{
_keyEquivalentModifierMask = aMask;
}
/*!
Sets the mask to be used with this button's key equivalent.
*/
- (unsigned)keyEquivalentModifierMask
{
return _keyEquivalentModifierMask;
}
/*!
Checks the button's key equivalent against that in the event, and if they
match simulates a button click.
*/
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
{
// Don't handle the key equivalent for the default window because the window will handle it for us
if ([[self window] defaultButton] === self)
return NO;
if (![anEvent _triggersKeyEquivalent:[self keyEquivalent] withModifierMask:[self keyEquivalentModifierMask]])
return NO;
[self performClick:nil];
return YES;
}
@end
@implementation CPButton (NS)
@@ -572,11 +652,16 @@ CPButtonStateMixed = CPThemeState("mixed");
@end
var CPButtonImageKey = @"CPButtonImageKey",
CPButtonAlternateImageKey = @"CPButtonAlternateImageKey",
CPButtonTitleKey = @"CPButtonTitleKey",
CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey",
CPButtonIsBorderedKey = @"CPButtonIsBorderedKey";
var CPButtonImageKey = @"CPButtonImageKey",
CPButtonAlternateImageKey = @"CPButtonAlternateImageKey",
CPButtonTitleKey = @"CPButtonTitleKey",
CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey",
CPButtonIsBorderedKey = @"CPButtonIsBorderedKey",
CPButtonAllowsMixedStateKey = @"CPButtonAllowsMixedStateKey",
CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey",
CPButtonImagePositionKey = @"CPButtonImagePositionKey",
CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey",
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey";
@implementation CPButton (CPCoding)
@@ -587,21 +672,31 @@ var CPButtonImageKey = @"CPButtonImageKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
_controlSize = CPRegularControlSize;
[self setImage:[aCoder decodeObjectForKey:CPButtonImageKey]];
[self setAlternateImage:[aCoder decodeObjectForKey:CPButtonAlternateImageKey]];
[self setTitle:[aCoder decodeObjectForKey:CPButtonTitleKey]];
[self setAlternateTitle:[aCoder decodeObjectForKey:CPButtonAlternateTitleKey]];
_title = [aCoder decodeObjectForKey:CPButtonTitleKey];
_alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
if ([aCoder containsValueForKey:CPButtonAllowsMixedStateKey])
_allowsMixedState = [aCoder decodeBoolForKey:CPButtonAllowsMixedStateKey];
[self setImageDimsWhenDisabled:[aCoder decodeObjectForKey:CPButtonImageDimsWhenDisabledKey]];
if ([aCoder containsValueForKey:CPButtonImagePositionKey])
[self setImagePosition:[aCoder decodeIntForKey:CPButtonImagePositionKey]];
if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey])
[self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])];
_keyEquivalentModifierMask = [aCoder decodeIntForKey:CPButtonKeyEquivalentMaskKey];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
return self;
}
@@ -613,11 +708,18 @@ var CPButtonImageKey = @"CPButtonImageKey",
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_image forKey:CPButtonImageKey];
[aCoder encodeObject:_alternateImage forKey:CPButtonAlternateImageKey];
[aCoder encodeObject:_title forKey:CPButtonTitleKey];
[aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey];
[aCoder encodeBool:_allowsMixedState forKey:CPButtonAllowsMixedStateKey];
[aCoder encodeBool:[self imageDimsWhenDisabled] forKey:CPButtonImageDimsWhenDisabledKey];
[aCoder encodeInt:[self imagePosition] forKey:CPButtonImagePositionKey];
if (_keyEquivalent)
[aCoder encodeObject:CFData.encodeBase64Utf16String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey];
[aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey];
}
@end
+236 -30
View File
@@ -1,11 +1,62 @@
@import <AppKit/CPView.j>
#include "CoreGraphics/CGGeometry.h"
@import "CPView.j"
@implementation CPButtonBar : CPControl
@implementation CPButtonBar : CPView
{
BOOL _hasResizeControl;
BOOL _resizeControlIsLeftAligned;
CPArray _buttons;
}
+ (id)plusButton
{
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)];
[button setBordered:NO];
[button setImage:image];
[button setImagePosition:CPImageOnly];
return button;
}
+ (id)minusButton
{
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
[button setBordered:NO];
[button setImage:image];
[button setImagePosition:CPImageOnly];
return button;
}
+ (id)actionPopupButton
{
var button = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"action_button.png"] size:CGSizeMake(22, 14)];
[button addItemWithTitle:nil];
[[button lastItem] setImage:image];
[button setImagePosition:CPImageOnly];
[button setValue:CGInsetMake(0, 0, 0, 0) forThemeAttribute:"content-inset"];
[button setPullsDown:YES];
return button;
}
+ (CPString)defaultThemeClass
{
return @"button-bar";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[CGInsetMake(0.0, 0.0, 0.0, 0.0), CGSizeMakeZero(), [CPNull null], [CPNull null], [CPNull null], [CPNull null]]
forKeys:[@"resize-control-inset", @"resize-control-size", @"resize-control-color", @"bezel-color", @"button-bezel-color", @"button-text-color"]];
}
- (id)initWithFrame:(CGRect)aFrame
@@ -13,59 +64,214 @@
self = [super initWithFrame:aFrame];
if (self)
{
_buttons = [];
[self setNeedsLayout];
}
return self;
}
+ (CPString)themeClass
- (void)awakeFromCib
{
return @"button-bar";
var view = [self superview],
subview = self;
while (view)
{
if ([view isKindOfClass:[CPSplitView class]])
{
var viewIndex = [[view subviews] indexOfObject:subview];
[view setButtonBar:self forDividerAtIndex:viewIndex];
break;
}
subview = view;
view = [view superview];
}
}
+ (id)themeAttributes
- (void)setButtons:(CPArray)buttons
{
return [CPDictionary dictionaryWithObjects:[[CPNull null]]
forKeys:[@"bezel-color"]];
_buttons = [CPArray arrayWithArray:buttons];
for (var i = 0, count = [_buttons count]; i < count; i++)
[_buttons[i] setBordered:YES];
[self setNeedsLayout];
}
- (CPArray)buttons
{
return [CPArray arrayWithArray:_buttons];
}
- (void)setHasResizeControl:(BOOL)shouldHaveResizeControl
{
if (_hasResizeControl === shouldHaveResizeControl)
return;
_hasResizeControl = !!shouldHaveResizeControl;
[self setNeedsLayout];
}
- (BOOL)hasResizeControl
{
return _hasResizeControl;
}
- (void)setResizeControlIsLeftAligned:(BOOL)shouldBeLeftAligned
{
if (_resizeControlIsLeftAligned === shouldBeLeftAligned)
return;
_resizeControlIsLeftAligned = !!shouldBeLeftAligned;
[self setNeedsLayout];
}
- (BOOL)resizeControlIsLeftAligned
{
return _resizeControlIsLeftAligned;
}
- (CGRect)resizeControlFrame
{
var inset = [self currentValueForThemeAttribute:@"resize-control-inset"],
size = [self currentValueForThemeAttribute:@"resize-control-size"],
currentSize = [self bounds],
leftOrigin = _resizeControlIsLeftAligned ? 0 : currentSize.size.width - size.width - inset.right - inset.left;
return CGRectMake(leftOrigin, 0, size.width + inset.left + inset.right, size.height + inset.top + inset.bottom);
}
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
{
if (aName === "bezel-view")
return [self bounds];
if (aName === "resize-control-view")
{
var inset = [self currentValueForThemeAttribute:@"resize-control-inset"],
size = [self currentValueForThemeAttribute:@"resize-control-size"],
currentSize = [self bounds];
if (_resizeControlIsLeftAligned)
return CGRectMake(inset.left, inset.top, size.width, size.height);
else
return CGRectMake(currentSize.size.width - size.width - inset.right, inset.top, size.width, size.height);
}
return [super rectForEphemeralSubviewNamed:aName];
}
- (CPView)createEphemeralSubviewNamed:(CPString)aName
{
if (aName === "bezel-view")
{
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
if (aName === "resize-control-view")
return [[CPView alloc] initWithFrame:CGRectMakeZero()];
[view setHitTests:NO];
return view;
}
return [super createEphemeralSubviewNamed:aName];
}
- (void)layoutSubviews
{
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:@""];
if (bezelView)
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
[self setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
var normalColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateNormal],
highlightedColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateHighlighted],
disabledColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateDisabled],
textColor = [self valueForThemeAttribute:@"button-text-color" inState:CPThemeStateNormal];
var buttonsNotHidden = [CPArray arrayWithArray:_buttons],
count = [buttonsNotHidden count];
while (count--)
if ([buttonsNotHidden[count] isHidden])
[buttonsNotHidden removeObject:buttonsNotHidden[count]];
var currentButtonOffset = _resizeControlIsLeftAligned ? CGRectGetMaxX([self bounds]) + 1 : -1,
bounds = [self bounds],
height = CGRectGetHeight(bounds) - 1,
frameWidth = CGRectGetWidth(bounds),
resizeRect = _hasResizeControl ? [self rectForEphemeralSubviewNamed:"resize-control-view"] : CGRectMakeZero(),
resizeWidth = CGRectGetWidth(resizeRect),
availableWidth = frameWidth - resizeWidth - 1;
for (var i = 0, count = [buttonsNotHidden count]; i < count; i++)
{
var button = buttonsNotHidden[i],
width = CGRectGetWidth([button frame]);
if (availableWidth > width)
availableWidth -= width;
else
break;
if (_resizeControlIsLeftAligned)
{
[button setFrame:CGRectMake(currentButtonOffset - width, 1, width, height)];
currentButtonOffset -= width - 1;
}
else
{
[button setFrame:CGRectMake(currentButtonOffset, 1, width, height)];
currentButtonOffset += width - 1;
}
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal | CPThemeStateBordered];
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted | CPThemeStateBordered];
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled | CPThemeStateBordered];
[button setValue:textColor forThemeAttribute:@"text-color" inState:CPThemeStateBordered];
// FIXME shouldn't need this
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
[self addSubview:button];
}
if (_hasResizeControl)
{
var resizeControlView = [self layoutEphemeralSubviewNamed:@"resize-control-view"
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:nil];
[resizeControlView setAutoresizingMask: _resizeControlIsLeftAligned ? CPViewMaxXMargin : CPViewMinXMargin];
[resizeControlView setBackgroundColor:[self currentValueForThemeAttribute:@"resize-control-color"]];
}
}
- (void)addSubview:(CPView)aSubview
- (void)setFrameSize:(CGSize)aSize
{
[super addSubview:aSubview];
[aSubview setAutoresizingMask:CPViewMinXMargin];
[super setFrameSize:aSize];
[self setNeedsLayout];
}
@end
var CPButtonBarHasResizeControlKey = @"CPButtonBarHasResizeControlKey",
CPButtonBarResizeControlIsLeftAlignedKey = @"CPButtonBarResizeControlIsLeftAlignedKey",
CPButtonBarButtonsKey = @"CPButtonBarButtonsKey";
@implementation CPButtonBar (CPCoding)
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeBool:_hasResizeControl forKey:CPButtonBarHasResizeControlKey];
[aCoder encodeBool:_resizeControlIsLeftAligned forKey:CPButtonBarResizeControlIsLeftAlignedKey];
[aCoder encodeObject:_buttons forKey:CPButtonBarButtonsKey];
}
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_buttons = [aCoder decodeObjectForKey:CPButtonBarButtonsKey] || [];
_hasResizeControl = [aCoder decodeBoolForKey:CPButtonBarHasResizeControlKey];
_resizeControlIsLeftAligned = [aCoder decodeBoolForKey:CPButtonBarResizeControlIsLeftAlignedKey];
}
return self;
}
@end
+27 -2
View File
@@ -23,6 +23,8 @@
@import "CPButton.j"
CPCheckBoxImageOffset = 4.0;
@implementation CPCheckBox : CPButton
{
}
@@ -37,7 +39,7 @@
return [self buttonWithTitle:aTitle];
}
+ (CPString)themeClass
+ (CPString)defaultThemeClass
{
return @"check-box";
}
@@ -55,10 +57,33 @@
[self setImagePosition:CPImageLeft];
[self setAlignment:CPLeftTextAlignment];
[self setBordered:YES];
[self setBordered:NO];
}
return self;
}
- (void)takeStateFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
var count = objects.length,
value = [objects[0] valueForKeyPath:aKeyPath] ? CPOnState : CPOffState;
[self setAllowsMixedState:NO];
[self setState:value];
while (count-- > 1)
{
if (value !== ([objects[count] valueForKeyPath:aKeyPath] ? CPOnState : CPOffState))
{
[self setAllowsMixedState:YES];
[self setState:CPMixedState];
}
}
}
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
[self takeStateFromKeyPath:aKeyPath ofObjects:objects];
}
@end
+64 -36
View File
@@ -22,14 +22,12 @@
@import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
/*!
/*!
@ingroup appkit
@class CPClipView
CPClipView allows you to define a clip rect and display only that portion of its containing view.
CPClipView allows you to define a clip rect and display only that portion of its containing view.
It is used to hold the document view in a CPScrollView.
*/
@implementation CPClipView : CPView
@@ -47,7 +45,7 @@
return;
var defaultCenter = [CPNotificationCenter defaultCenter];
if (_documentView)
{
[defaultCenter
@@ -59,29 +57,29 @@
removeObserver:self
name:CPViewBoundsDidChangeNotification
object:_documentView];
[_documentView removeFromSuperview];
}
_documentView = aView;
if (_documentView)
{
[self addSubview:_documentView];
[_documentView setPostsFrameChangedNotifications:YES];
[_documentView setPostsBoundsChangedNotifications:YES];
[defaultCenter
[_documentView setPostsFrameChangedNotifications:YES];
[_documentView setPostsBoundsChangedNotifications:YES];
[defaultCenter
addObserver:self
selector:@selector(viewFrameChanged:)
name:CPViewFrameDidChangeNotification
name:CPViewFrameDidChangeNotification
object:_documentView];
[defaultCenter
[defaultCenter
addObserver:self
selector:@selector(viewBoundsChanged:)
name:CPViewBoundsDidChangeNotification
name:CPViewBoundsDidChangeNotification
object:_documentView];
}
}
@@ -106,7 +104,7 @@
return _CGPointMakeZero();
var documentFrame = [_documentView frame];
aPoint.x = MAX(0.0, MIN(aPoint.x, MAX(_CGRectGetWidth(documentFrame) - _CGRectGetWidth(_bounds), 0.0)));
aPoint.y = MAX(0.0, MIN(aPoint.y, MAX(_CGRectGetHeight(documentFrame) - _CGRectGetHeight(_bounds), 0.0)));
@@ -117,12 +115,16 @@
{
if (_CGPointEqualToPoint(_bounds.origin, aPoint))
return;
[super setBoundsOrigin:aPoint];
var superview = [self superview];
if([superview isKindOfClass:[CPScrollView class]])
var superview = [self superview],
// This is hack to avoid having to import CPScrollView.
// FIXME: Should CPScrollView be finding out about this on its own somehow?
scrollViewClass = objj_getClass("CPScrollView");
if ([superview isKindOfClass:scrollViewClass])
[superview reflectScrolledClipView:self];
}
@@ -162,37 +164,63 @@
- (void)_constrainScrollPoint
{
var oldScrollPoint = [self bounds].origin;
// Call scrollToPoint: because the current scroll point may no longer make
// Call scrollToPoint: because the current scroll point may no longer make
// sense given the new frame of the document view.
[self scrollToPoint:oldScrollPoint];
// scrollToPoint: takes care of reflectScrollClipView: for us, so bail if
// scrollToPoint: takes care of reflectScrollClipView: for us, so bail if
// the scroll points are not equal (meaning scrollToPoint: didn't early bail).
if (!CGPointEqualToPoint(oldScrollPoint, [self bounds].origin))
return;
// ... and we're in a scroll view of course.
var superview = [self superview];
if ([superview isKindOfClass:[CPScrollView class]])
var superview = [self superview],
// This is hack to avoid having to import CPScrollView.
// FIXME: Should CPScrollView be finding out about this on its own somehow?
scrollViewClass = objj_getClass("CPScrollView");
if ([superview isKindOfClass:scrollViewClass])
[superview reflectScrolledClipView:self];
}
- (BOOL)autoscroll:(CPEvent)anEvent
- (BOOL)autoscroll:(CPEvent)anEvent
{
var bounds = [self bounds],
eventLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil];
eventLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil],
superview = [self superview],
deltaX = 0,
deltaY = 0;
if (CPRectContainsPoint(bounds, eventLocation))
if (CGRectContainsPoint(bounds, eventLocation))
return NO;
var newRect = CGRectMakeZero();
if (![superview isKindOfClass:[CPScrollView class]] || [superview hasVerticalScroller])
{
if (eventLocation.y < CGRectGetMinY(bounds))
deltaY = CGRectGetMinY(bounds) - eventLocation.y;
else if (eventLocation.y > CGRectGetMaxY(bounds))
deltaY = CGRectGetMaxY(bounds) - eventLocation.y;
if (deltaY < -bounds.size.height)
deltaY = -bounds.size.height;
if (deltaY > bounds.size.height)
deltaY = bounds.size.height;
}
newRect.origin = eventLocation;
newRect.size = CPSizeMake(10, 10);
if (![superview isKindOfClass:[CPScrollView class]] || [superview hasHorizontalScroller])
{
if (eventLocation.x < CGRectGetMinX(bounds))
deltaX = CGRectGetMinX(bounds) - eventLocation.x;
else if (eventLocation.x > CGRectGetMaxX(bounds))
deltaX = CGRectGetMaxX(bounds) - eventLocation.x;
if (deltaX < -bounds.size.width)
deltaX = -bounds.size.width;
if (deltaX > bounds.size.width)
deltaX = bounds.size.width;
}
return [_documentView scrollRectToVisible:newRect];
return [self scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
}
@end
@@ -206,14 +234,14 @@ var CPClipViewDocumentViewKey = @"CPScrollViewDocumentView";
{
if (self = [super initWithCoder:aCoder])
[self setDocumentView:[aCoder decodeObjectForKey:CPClipViewDocumentViewKey]];
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_documentView forKey:CPClipViewDocumentViewKey];
}
+245 -124
View File
@@ -30,16 +30,16 @@
@import "CPCollectionViewItem.j"
/*!
/*!
@ingroup appkit
@class CPCollectionView
This class displays an array as a grid of objects, where each object is represented by a view.
The view is controlled by creating a CPCollectionViewItem and specifying its view, then
This class displays an array as a grid of objects, where each object is represented by a view.
The view is controlled by creating a CPCollectionViewItem and specifying its view, then
setting that item as the collection view prototype.
@par Delegate Methods
@delegate -(void)collectionViewDidChangeSelection:(CPCollectionView)collectionView;
Called when the selection in the collection view has changed.
@param collectionView the collection view who's selection changed
@@ -67,35 +67,35 @@
{
CPArray _content;
CPArray _items;
CPData _itemData;
CPCollectionViewItem _itemPrototype;
CPCollectionViewItem _itemForDragging;
CPMutableArray _cachedItems;
unsigned _maxNumberOfRows;
unsigned _maxNumberOfColumns;
CGSize _minItemSize;
CGSize _maxItemSize;
CPArray _backgroundColors;
float _tileWidth;
BOOL _isSelectable;
BOOL _allowsMultipleSelection;
BOOL _allowsEmptySelection;
CPIndexSet _selectionIndexes;
CGSize _itemSize;
float _horizontalMargin;
float _verticalMargin;
unsigned _numberOfRows;
unsigned _numberOfColumns;
id _delegate;
CPEvent _mouseDownEvent;
@@ -104,14 +104,14 @@
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_items = [];
_content = [];
_cachedItems = [];
_itemSize = CGSizeMakeZero();
_minItemSize = CGSizeMakeZero();
_maxItemSize = CGSizeMakeZero();
@@ -120,12 +120,12 @@
_verticalMargin = 5.0;
_tileWidth = -1.0;
_selectionIndexes = [CPIndexSet indexSet];
_allowsEmptySelection = YES;
_isSelectable = YES;
}
return self;
}
@@ -196,8 +196,8 @@
// Setting the Content
/*!
Sets the content of the collection view to the content in \c anArray.
This array can be of any type, and each element will be passed to the \c -setRepresentedObject: method.
Sets the content of the collection view to the content in \c anArray.
This array can be of any type, and each element will be passed to the \c -setRepresentedObject: method.
It's the responsibility of your custom collection view item to interpret the object.
@param anArray the content array
*/
@@ -205,9 +205,9 @@
{
if (_content == anArray)
return;
_content = anArray;
[self reloadContent];
}
@@ -236,13 +236,13 @@
{
if (_isSelectable == isSelectable)
return;
_isSelectable = isSelectable;
if (!_isSelectable)
{
var index = CPNotFound;
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:NO];
}
@@ -297,23 +297,25 @@
*/
- (void)setSelectionIndexes:(CPIndexSet)anIndexSet
{
if (_selectionIndexes == anIndexSet || !_isSelectable)
if ([_selectionIndexes isEqual:anIndexSet] || !_isSelectable)
return;
var index = CPNotFound;
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:NO];
_selectionIndexes = anIndexSet;
var index = CPNotFound;
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:YES];
[[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)])
[_delegate collectionViewDidChangeSelection:self]
[_delegate collectionViewDidChangeSelection:self];
}
/*!
@@ -326,10 +328,10 @@
/* @ignore */
- (void)reloadContent
{
{
// Remove current views
var count = _items.length;
while (count--)
{
[[_items[count] view] removeFromSuperview];
@@ -337,7 +339,7 @@
_cachedItems.push(_items[count]);
}
_items = [];
if (!_itemPrototype || !_content)
@@ -350,7 +352,7 @@
for (; index < count; ++index)
{
_items.push([self newItemForRepresentedObject:_content[index]]);
[self addSubview:[_items[index] view]];
}
@@ -365,49 +367,49 @@
- (void)tile
{
var width = CGRectGetWidth([self bounds]);
if (![_content count] || width == _tileWidth)
return;
// We try to fit as many views per row as possible. Any remaining space is then
// We try to fit as many views per row as possible. Any remaining space is then
// either proportioned out to the views (if their minSize != maxSize) or used as
// margin
var itemSize = CGSizeMakeCopy(_minItemSize);
_numberOfColumns = MAX(1.0, FLOOR(width / itemSize.width));
if (_maxNumberOfColumns > 0)
_numberOfColumns = MIN(_maxNumberOfColumns, _numberOfColumns);
var remaining = width - _numberOfColumns * itemSize.width,
itemsNeedSizeUpdate = NO;
if (remaining > 0 && itemSize.width < _maxItemSize.width)
itemSize.width = MIN(_maxItemSize.width, itemSize.width + FLOOR(remaining / _numberOfColumns));
// When we ONE column and a non-integral width, the FLOORing above can cause the item width to be smaller than the total width.
if (_maxNumberOfColumns == 1 && itemSize.width < _maxItemSize.width && itemSize.width < width)
itemSize.width = MIN(_maxItemSize.width, width);
if (!CGSizeEqualToSize(_itemSize, itemSize))
{
_itemSize = itemSize;
itemsNeedSizeUpdate = YES;
}
var index = 0,
count = _items.length;
if (_maxNumberOfColumns > 0 && _maxNumberOfRows > 0)
count = MIN(count, _maxNumberOfColumns * _maxNumberOfRows);
_numberOfRows = CEIL(count / _numberOfColumns);
_horizontalMargin = FLOOR((width - _numberOfColumns * itemSize.width) / (_numberOfColumns + 1));
var x = _horizontalMargin,
y = -itemSize.height;
for (; index < count; ++index)
{
if (index % _numberOfColumns == 0)
@@ -415,19 +417,28 @@
x = _horizontalMargin;
y += _verticalMargin + itemSize.height;
}
var view = [_items[index] view];
[view setFrameOrigin:CGPointMake(x, y)];
if (itemsNeedSizeUpdate)
[view setFrameSize:_itemSize];
x += itemSize.width + _horizontalMargin;
}
var superview = [self superview],
proposedHeight = y + itemSize.height + _verticalMargin;
if ([superview isKindOfClass:[CPClipView class]])
{
var superviewSize = [superview bounds].size;
proposedHeight = MAX(superviewSize.height, proposedHeight);
}
_tileWidth = width;
[self setFrameSize:CGSizeMake(width, y + itemSize.height + _verticalMargin)];
[self setFrameSize:CGSizeMake(width, proposedHeight)];
_tileWidth = -1.0;
}
@@ -445,9 +456,9 @@
{
if (_maxNumberOfRows == aMaxNumberOfRows)
return;
_maxNumberOfRows = aMaxNumberOfRows;
[self tile];
}
@@ -467,9 +478,9 @@
{
if (_maxNumberOfColumns == aMaxNumberOfColumns)
return;
_maxNumberOfColumns = aMaxNumberOfColumns;
[self tile];
}
@@ -506,9 +517,9 @@
{
if (CGSizeEqualToSize(_minItemSize, aSize))
return;
_minItemSize = CGSizeMakeCopy(aSize);
[self tile];
}
@@ -528,9 +539,9 @@
{
if (CGSizeEqualToSize(_maxItemSize, aSize))
return;
_maxItemSize = CGSizeMakeCopy(aSize);
[self tile];
}
@@ -582,14 +593,51 @@
index = row * _numberOfColumns + column;
if (index >= 0 && index < _items.length)
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
{
if (_allowsMultipleSelection && ([anEvent modifierFlags] & CPCommandKeyMask || [anEvent modifierFlags] & CPShiftKeyMask))
{
if ([anEvent modifierFlags] & CPCommandKeyMask)
{
var indexes = [_selectionIndexes copy];
if ([indexes containsIndex:index])
[indexes removeIndex:index];
else
[indexes addIndex:index];
}
else if ([anEvent modifierFlags] & CPShiftKeyMask)
{
var firstSelectedIndex = [[self selectionIndexes] firstIndex],
newSelectedRange = nil;
if (index < firstSelectedIndex)
newSelectedRange = CPMakeRange(index, (firstSelectedIndex - index) + 1);
else
newSelectedRange = CPMakeRange(firstSelectedIndex, (index - firstSelectedIndex) + 1);
indexes = [[self selectionIndexes] copy];
[indexes addIndexesInRange:newSelectedRange];
}
}
else
indexes = [CPIndexSet indexSetWithIndex:index];
[self setSelectionIndexes:indexes];
}
else if (_allowsEmptySelection)
[self setSelectionIndexes:[CPIndexSet indexSet]];
}
- (void)mouseDragged:(CPEvent)anEvent
{
var locationInWindow = [anEvent locationInWindow],
mouseDownLocationInWindow = [_mouseDownEvent locationInWindow];
// FIXME: This is because Safari's drag hysteresis is 3px x 3px
if ((ABS(locationInWindow.x - mouseDownLocationInWindow.x) < 3) &&
(ABS(locationInWindow.y - mouseDownLocationInWindow.y) < 3))
return;
if (![_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)])
return;
@@ -597,13 +645,15 @@
if (![_selectionIndexes count])
return;
if ([_delegate respondsToSelector:@selector(collectionView:canDragItemsAtIndexes:withEvent:)] &&
![_delegate collectionView:self canDragItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent])
return;
// Set up the pasteboard
var dragTypes = [_delegate collectionView:self dragTypesForItemsAtIndexes:_selectionIndexes];
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self];
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if (!_itemForDragging)
_itemForDragging = [self newItemForRepresentedObject:_content[[_selectionIndexes firstIndex]]];
else
@@ -644,9 +694,9 @@
{
if (_verticalMargin == aVerticalMargin)
return;
_verticalMargin = aVerticalMargin;
[self tile];
}
@@ -676,92 +726,132 @@
return _delegate;
}
- (CPCollectionViewItem)itemAtIndex:(unsigned)anIndex
{
return [_items objectAtIndex:anIndex];
}
- (CGRect)frameForItemAtIndex:(unsigned)anIndex
{
return [[[self itemAtIndex:anIndex] view] frame];
}
- (CGRect)frameForItemsAtIndexes:(CPIndexSet)anIndexSet
{
var indexArray = [],
frame = CGRectNull;
[anIndexSet getIndexes:indexArray maxCount:-1 inIndexRange:nil];
var index = 0,
count = [indexArray count];
for (; index < count; ++index)
frame = CGRectUnion(frame, [self frameForItemAtIndex:indexArray[index]]);
return frame;
}
@end
@implementation CPCollectionView (KeyboardInteraction)
- (CGRect)rectForItemAtIndex:(int)index
- (void)_modifySelectionWithNewIndex:(int)anIndex direction:(int)aDirection expand:(BOOL)shouldExpand
{
// Don't re-compute anything just grab the current frame
// This allows subclasses to override tile without messing this up.
return [[_items[index] view] frame];
}
anIndex = MIN(MAX(anIndex, 0), [[self items] count] - 1);
- (CGRect)rectForItemsAtIndexes:(CPIndexSet)indexSet
{
var indexArray = [],
rect = nil;
[indexSet getIndexes:indexArray maxCount:-1 inIndexRange:nil];
for (var i = 0, count = indexArray.length; i < count; ++i)
if (_allowsMultipleSelection && shouldExpand)
{
var index = indexArray[i];
if (rect == nil)
rect = [self rectForItemAtIndex:index];
else
rect = CGRectUnion(rect, [self rectForItemAtIndex:index]);
}
var indexes = [_selectionIndexes copy],
bottomAnchor = [indexes firstIndex],
topAnchor = [indexes lastIndex];
return rect;
// if the direction is backward (-1) check with the bottom anchor
if (aDirection === -1)
[indexes addIndexesInRange:CPMakeRange(anIndex, bottomAnchor - anIndex + 1)];
else
[indexes addIndexesInRange:CPMakeRange(topAnchor, anIndex - topAnchor + 1)];
}
else
indexes = [CPIndexSet indexSetWithIndex:anIndex];
[self setSelectionIndexes:indexes];
[self _scrollToSelection];
}
- (void)_scrollToSelection
{
var rect = [self rectForItemsAtIndexes:[self selectionIndexes]];
if (rect)
[self scrollRectToVisible:rect];
var frame = [self frameForItemsAtIndexes:[self selectionIndexes]];
if (!CGRectIsNull(frame))
[self scrollRectToVisible:frame];
}
- (void)moveLeft:(id)sender
{
var index = [[self selectionIndexes] firstIndex];
if (index === CPNotFound)
if (index === CPNotFound)
index = [[self items] count];
index = MAX(index - 1, 0);
[self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:NO];
}
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
- (void)moveLeftAndModifySelection:(id)sender
{
var index = [[self selectionIndexes] firstIndex];
if (index === CPNotFound)
index = [[self items] count];
[self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:YES];
}
- (void)moveRight:(id)sender
{
var index = MIN([[self selectionIndexes] firstIndex] + 1, [[self items] count]-1);
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:NO];
}
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
- (void)moveRightAndModifySelection:(id)sender
{
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:YES];
}
- (void)moveDown:(id)sender
{
var index = MIN([[self selectionIndexes] firstIndex] + [self numberOfColumns], [[self items] count]-1);
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:NO];
}
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
- (void)moveDownAndModifySelection:(id)sender
{
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:YES];
}
- (void)moveUp:(id)sender
{
var index = [[self selectionIndexes] firstIndex];
if (index == CPNotFound)
if (index == CPNotFound)
index = [[self items] count];
index = MAX(0, index - [self numberOfColumns]);
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
[self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:NO];
}
- (void)deleteBackwards:(id)sender
- (void)moveUpAndModifySelection:(id)sender
{
var index = [[self selectionIndexes] firstIndex];
if (index == CPNotFound)
index = [[self items] count];
[self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:YES];
}
- (void)deleteBackward:(id)sender
{
if ([[self delegate] respondsToSelector:@selector(collectionView:shouldDeleteItemsAtIndexes:)])
{
[[self delegate] collectionView:self shouldDeleteItemsAtIndexes:[self selectionIndexes]];
var index = [[self selectionIndexes] firstIndex];
if (index > [[self content] count]-1)
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count]-1]];
if (index > [[self content] count] - 1)
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count] - 1]];
[self _scrollToSelection];
[self setNeedsDisplay:YES];
@@ -775,11 +865,34 @@
@end
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
@implementation CPCollectionView (Deprecated)
- (CGRect)rectForItemAtIndex:(int)anIndex
{
_CPReportLenientDeprecation([self class], _cmd, @selector(frameForItemAtIndex:));
// Don't re-compute anything just grab the current frame
// This allows subclasses to override tile without messing this up.
return [self frameForItemAtIndex:anIndex];
}
- (CGRect)rectForItemsAtIndexes:(CPIndexSet)anIndexSet
{
_CPReportLenientDeprecation([self class], _cmd, @selector(frameForItemsAtIndexes:));
return [self frameForItemsAtIndexes:anIndexSet];
}
@end
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
CPCollectionViewMaxNumberOfRowsKey = @"CPCollectionViewMaxNumberOfRowsKey",
CPCollectionViewMaxNumberOfColumnsKey = @"CPCollectionViewMaxNumberOfColumnsKey",
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
CPCollectionViewAllowsMultipleSelectionKey = @"CPCollectionViewAllowsMultipleSelectionKey",
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
@implementation CPCollectionView (CPCoding)
@@ -796,20 +909,24 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
_cachedItems = [];
_itemSize = CGSizeMakeZero();
_minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero();
_maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero();
_maxNumberOfRows = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfRowsKey] || 0;
_maxNumberOfColumns = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfColumnsKey] || 0;
_verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey];
_isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey];
_allowsMultipleSelection = [aCoder decodeBoolForKey:CPCollectionViewAllowsMultipleSelectionKey];
[self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]];
_tileWidth = -1.0;
_selectionIndexes = [CPIndexSet indexSet];
_allowsEmptySelection = YES;
}
@@ -822,12 +939,16 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
if (!CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
[aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey];
if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
[aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
[aCoder encodeInt:_maxNumberOfRows forKey:CPCollectionViewMaxNumberOfRowsKey];
[aCoder encodeInt:_maxNumberOfColumns forKey:CPCollectionViewMaxNumberOfColumnsKey];
[aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey];
[aCoder encodeBool:_allowsMultipleSelection forKey:CPCollectionViewAllowsMultipleSelectionKey];
[aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
[aCoder encodeObject:_backgroundColors forKey:CPCollectionViewBackgroundColorsKey];
+1
View File
@@ -22,6 +22,7 @@
@import "CPViewController.j"
/*!
Represents an object inside a CPCollectionView.
*/
+97 -147
View File
@@ -32,7 +32,7 @@ var _redComponent = 0,
_greenComponent = 1,
_blueComponent = 2,
_alphaCompnent = 3;
var _hueComponent = 0,
_saturationComponent = 1,
_brightnessComponent = 2;
@@ -54,27 +54,21 @@ var cachedBlackColor,
cachedShadowColor,
cachedClearColor;
/*!
/*!
@ingroup appkit
@code CPColor
\c CPColor can be used to represent color
in an RGB or HSB model with an optional transparency value.</p>
<p>It also provides some class helper methods that
returns instances of commonly used colors.</p>
<p>The class does not have a \c -set: method
like NextStep based frameworks to change the color of
the current context. To change the color of the current
context, use CGContextSetFillColor().
*/
@implementation CPColor : CPObject
{
CPArray _components;
CPImage _patternImage;
CPString _cssString;
CPString _cssString;
}
/*!
@@ -82,12 +76,12 @@ var cachedBlackColor,
Each component should be between the range of 0.0 to 1.0. For
the alpha component, a value of 1.0 is opaque, and 0.0 means
completely transparent.
@param red the red component of the color
@param green the green component of the color
@param blue the blue component of the color
@param alpha the alpha component
@return a color initialized to the values specified
*/
+ (CPColor)colorWithRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
@@ -97,17 +91,17 @@ var cachedBlackColor,
/*!
@deprecated in favor of colorWithRed:green:blue:alpha:
Creates a color in the RGB color space, with an alpha value.
Each component should be between the range of 0.0 to 1.0. For
the alpha component, a value of 1.0 is opaque, and 0.0 means
completely transparent.
@param red the red component of the color
@param green the green component of the color
@param blue the blue component of the color
@param alpha the alpha component
@return a color initialized to the values specified
*/
+ (CPColor)colorWithCalibratedRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
@@ -119,10 +113,10 @@ var cachedBlackColor,
/*!
Creates a new color object with \c white for the RGB components.
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
@param white a float between 0.0 and 1.0
@param alpha the alpha component between 0.0 and 1.0
@return a color initialized to the values specified
*/
+ (CPColor)colorWithWhite:(float)white alpha:(float)alpha
@@ -132,13 +126,13 @@ var cachedBlackColor,
/*!
@deprecated in favor of colorWithWhite:apha:
Creates a new color object with \c white for the RGB components.
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
@param white a float between 0.0 and 1.0
@param alpha the alpha component between 0.0 and 1.0
@return a color initialized to the values specified
*/
+ (CPColor)colorWithCalibratedWhite:(float)white alpha:(float)alpha
@@ -148,11 +142,11 @@ var cachedBlackColor,
/*!
Creates a new color in HSB space.
@param hue the hue value
@param saturation the saturation value
@param brightness the brightness value
@return the initialized color
*/
+ (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness
@@ -162,16 +156,16 @@ var cachedBlackColor,
+ (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness alpha:(float)alpha
{
if(saturation === 0.0)
if (saturation === 0.0)
return [CPColor colorWithCalibratedWhite:brightness / 100.0 alpha:alpha];
var f = hue % 60,
p = (brightness * (100 - saturation)) / 10000,
q = (brightness * (6000 - saturation * f)) / 600000,
t = (brightness * (6000 - saturation * (60 -f))) / 600000,
b = brightness / 100.0;
switch(FLOOR(hue / 60))
switch (FLOOR(hue / 60))
{
case 0: return [CPColor colorWithCalibratedRed: b green: t blue: p alpha: alpha];
case 1: return [CPColor colorWithCalibratedRed: q green: b blue: p alpha: alpha];
@@ -186,7 +180,7 @@ var cachedBlackColor,
Creates an RGB color from a hexadecimal string. For example,
the a string of "FFFFFF" would return a white CPColor.
"FF0000" would return a pure red, "00FF00" would return a
pure blue, and "0000FF" would return a pure green.
pure blue, and "0000FF" would return a pure green.
@param hex a 6 character long string of hex
@@ -194,7 +188,8 @@ var cachedBlackColor,
*/
+ (CPColor)colorWithHexString:(string)hex
{
return [[CPColor alloc] _initWithRGBA: hexToRGB(hex)];
var rgba = hexToRGB(hex);
return rgba ? [[CPColor alloc] _initWithRGBA: rgba] : null;
}
/*!
@@ -397,7 +392,7 @@ var cachedBlackColor,
/*!
Creates a CPColor from a valid CSS RGB string. Example, "rgb(32,64,129)".
@param aString a CSS color string
@return a color initialized to the value in the css string
*/
@@ -409,23 +404,23 @@ var cachedBlackColor,
/* @ignore */
- (id)_initWithCSSString:(CPString)aString
{
if(aString.indexOf("rgb") == CPNotFound)
if (aString.indexOf("rgb") == CPNotFound)
return nil;
self = [super init];
var startingIndex = aString.indexOf("(");
var parts = aString.substring(startingIndex+1).split(',');
var startingIndex = aString.indexOf("("),
parts = aString.substring(startingIndex + 1).split(',');
_components = [
parseInt(parts[0], 10) / 255.0,
parseInt(parts[1], 10) / 255.0,
parseInt(parts[2], 10) / 255.0,
parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0
]
parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0
];
_cssString = aString;
return self;
}
@@ -433,55 +428,20 @@ var cachedBlackColor,
- (id)_initWithRGBA:(CPArray)components
{
self = [super init];
if (self)
{
_components = components;
if (!CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0 && window.Base64 && window.CRC32)
{
var bytes = [0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x8,0x3,0x0,0x0,0x0,0x28,0xcb,0x34,0xbb,0x0,0x0,0x3,0x0,0x50,0x4c,0x54,0x45,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x17,0x89,0x99,0x55,0x0,0x0,0x0,0x1,0x74,0x52,0x4e,0x53,0x0,0x40,0xe6,0xd8,0x66,0x0,0x0,0x0,0x10,0x49,0x44,0x41,0x54,0x78,0xda,0x62,0x60,0x0,0x0,0x0,0x0,0xff,0xff,0x3,0x0,0x0,0x2,0x0,0x1,0x24,0x7f,0x24,0xf1,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82,0xff];
var r_off = 41;
var g_off = 42;
var b_off = 43;
var a_off = 821;
var plte_crc_off = 809;
var trns_crc_off = 822;
var plte_type_off = 37;
var trns_type_off = 817;
bytes[r_off] = Math.round(_components[0]*255);
bytes[g_off] = Math.round(_components[1]*255);
bytes[b_off] = Math.round(_components[2]*255);
bytes[a_off] = Math.round(_components[3]*255);
// calculate new CRCs
var new_plte_crc = integerToBytes(CRC32.getCRC(bytes, plte_type_off, 4+768), 4);
var new_trns_crc = integerToBytes(CRC32.getCRC(bytes, trns_type_off, 4+1), 4);
// overwrite old CRCs with new ones
for (var i = 0; i < 4; i++)
{
bytes[plte_crc_off+i] = new_plte_crc[i];
bytes[trns_crc_off+i] = new_trns_crc[i];
}
// Base64 encode, strip whitespace and build data URL
var base64image = Base64.encode(bytes); //.replace(/[\s]/g, "");
_cssString = "url(\"data:image/png;base64," + base64image + "\")";
}
else
{
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
parseInt(_components[0] * 255.0) + ", " +
parseInt(_components[1] * 255.0) + ", " +
parseInt(_components[2] * 255.0) +
(hasAlpha ? (", " + _components[3]) : "") + ")";
}
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
parseInt(_components[0] * 255.0) + ", " +
parseInt(_components[1] * 255.0) + ", " +
parseInt(_components[2] * 255.0) +
(hasAlpha ? (", " + _components[3]) : "") + ")";
}
return self;
}
@@ -489,13 +449,14 @@ var cachedBlackColor,
- (id)_initWithPatternImage:(CPImage)anImage
{
self = [super init];
if (self)
{
_patternImage = anImage;
_cssString = "url(\"" + [_patternImage filename] + "\")";
_components = [0.0, 0.0, 0.0, 1.0];
}
return self;
}
@@ -557,17 +518,17 @@ var cachedBlackColor,
/*!
Returns a new color with the same RGB as the receiver but a new alpha component.
@param anAlphaComponent the alpha component for the new color
@return a new color object
*/
- (CPColor)colorWithAlphaComponent:(float)anAlphaComponent
{
var components = _components.slice();
components[components.length - 1] = anAlphaComponent;
return [[[self class] alloc] _initWithRGBA:components];
}
@@ -586,37 +547,40 @@ var cachedBlackColor,
var red = ROUND(_components[_redComponent] * 255.0),
green = ROUND(_components[_greenComponent] * 255.0),
blue = ROUND(_components[_blueComponent] * 255.0);
var max = MAX(red, green, blue),
min = MIN(red, green, blue),
delta = max - min;
var brightness = max / 255.0,
saturation = (max != 0) ? delta / max : 0;
var hue;
if(saturation == 0)
if (saturation == 0)
{
hue = 0;
}
else
{
var rr = (max - red) / delta;
var gr = (max - green) / delta;
var br = (max - blue) / delta;
if (red == max)
var rr = (max - red) / delta,
gr = (max - green) / delta,
br = (max - blue) / delta;
if (red == max)
hue = br - gr;
else if (green == max)
else if (green == max)
hue = 2 + rr - br;
else
else
hue = 4 + gr - rr;
hue /= 6;
if (hue < 0)
if (hue < 0)
hue++;
}
return [
ROUND(hue * 360.0),
ROUND(hue * 360.0),
ROUND(saturation * 100.0),
ROUND(brightness * 100.0)
];
@@ -664,7 +628,7 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
@implementation CPColor (CoreGraphicsExtensions)
/*!
/*!
Set's the receiver to be the fill and stroke color in the current graphics context
*/
- (void)set
@@ -673,16 +637,16 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
[self setStroke];
}
/*!
/*!
Set's the receiver to be the fill color in the current graphics context
*/
- (void)setFill
{
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSetFillColor(ctx, self);
CGContextSetFillColor(ctx, self);
}
/*!
/*!
Set's the receiver to be the stroke color in the current graphics context
*/
- (void)setStroke
@@ -715,7 +679,7 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
{
if ([aCoder containsValueForKey:CPColorPatternImageKey])
return [self _initWithPatternImage:[aCoder decodeObjectForKey:CPColorPatternImageKey]];
return [self _initWithRGBA:[aCoder decodeObjectForKey:CPColorComponentsKey]];
}
@@ -733,10 +697,8 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
@end
var hexCharacters = "0123456789ABCDEF";
// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior
var hexToRGB, integerToBytes, rgbToHex, byteToHex;
var hexCharacters = "0123456789ABCDEF";
/*!
Used for the CPColor \c +colorWithHexString: implementation
@@ -744,51 +706,39 @@ var hexToRGB, integerToBytes, rgbToHex, byteToHex;
@class CPColor
@return an array of rgb components
*/
function hexToRGB(hex)
var hexToRGB = function(hex)
{
if ( hex.length == 3 )
if (hex.length == 3)
hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
if(hex.length != 6)
if (hex.length != 6)
return null;
hex = hex.toUpperCase();
for(var i=0; i<hex.length; i++)
if(hexCharacters.indexOf(hex.charAt(i)) == -1)
for (var i = 0; i < hex.length; i++)
if (hexCharacters.indexOf(hex.charAt(i)) == -1)
return null;
var red = (hexCharacters.indexOf(hex.charAt(0)) * 16 + hexCharacters.indexOf(hex.charAt(1))) / 255.0;
var green = (hexCharacters.indexOf(hex.charAt(2)) * 16 + hexCharacters.indexOf(hex.charAt(3))) / 255.0;
var blue = (hexCharacters.indexOf(hex.charAt(4)) * 16 + hexCharacters.indexOf(hex.charAt(5))) / 255.0;
var red = (hexCharacters.indexOf(hex.charAt(0)) * 16 + hexCharacters.indexOf(hex.charAt(1))) / 255.0,
green = (hexCharacters.indexOf(hex.charAt(2)) * 16 + hexCharacters.indexOf(hex.charAt(3))) / 255.0,
blue = (hexCharacters.indexOf(hex.charAt(4)) * 16 + hexCharacters.indexOf(hex.charAt(5))) / 255.0;
return [red, green, blue, 1.0];
}
};
function integerToBytes(integer, length) {
if (!length)
length = (integer == 0) ? 1 : Math.round((Math.log(integer)/Math.log(2))/8+0.5);
var bytes = new Array(length);
for (var i = length-1; i >= 0; i--) {
bytes[i] = integer & 255;
integer = integer >> 8
}
return bytes;
}
function rgbToHex(r,g,b) {
var rgbToHex = function(r,g,b)
{
return byteToHex(r) + byteToHex(g) + byteToHex(b);
}
};
function byteToHex(n) {
if (!n || isNaN(n)) return "00";
n = ROUND(MIN(255,MAX(0,256*n)));
return hexCharacters.charAt((n - n % 16) / 16) +
hexCharacters.charAt(n % 16);
}
var byteToHex = function(n)
{
if (!n || isNaN(n))
return "00";
// Toll-Free bridge CPColor to CGColor.
//CGColor.prototype.isa = CPColor;
//[CPColor initialize];
n = FLOOR(MIN(255, MAX(0, 256 * n)));
//http://dev.mootools.net/browser/trunk/Source/Utilities/Color.js?rev=1184
return hexCharacters.charAt((n - n % 16) / 16) +
hexCharacters.charAt(n % 16);
};
+83 -80
View File
@@ -20,11 +20,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPApplication.j"
@import "CPButton.j"
@import "CPCookie.j"
@import "CPPanel.j"
@import "CPView.j"
CPColorPanelColorDidChangeNotification = @"CPColorPanelColorDidChangeNotification";
var PREVIEW_HEIGHT = 20.0,
@@ -35,7 +37,7 @@ var PREVIEW_HEIGHT = 20.0,
var SharedColorPanel = nil,
ColorPickerClasses = [];
/*
A color wheel
@global
@@ -52,7 +54,7 @@ CPSliderColorPickerMode = 2;
CPColorPickerViewWidth = 265,
CPColorPickerViewHeight = 370;
/*!
/*!
@ingroup appkit
@class CPColorPanel
@@ -61,7 +63,7 @@ CPColorPickerViewHeight = 370;
obtain the panel, call the \c +sharedColorPanel method.
*/
@implementation CPColorPanel : CPPanel
{
{
_CPColorPanelToolbar _toolbar;
_CPColorPanelSwatches _swatchView;
_CPColorPanelPreview _previewView;
@@ -80,8 +82,8 @@ CPColorPickerViewHeight = 370;
int _mode;
}
/*!
A list of color pickers is collected here, and any color panel created will contain
/*!
A list of color pickers is collected here, and any color panel created will contain
any picker in this list up to this point. In other words, call before creating a color panel.
*/
+ (void)provideColorPickerClass:(Class)aColorPickerSubclass
@@ -96,7 +98,7 @@ CPColorPickerViewHeight = 370;
{
if (!SharedColorPanel)
SharedColorPanel = [[CPColorPanel alloc] init];
return SharedColorPanel;
}
@@ -107,7 +109,7 @@ CPColorPickerViewHeight = 370;
+ (void)setPickerMode:(CPColorPanelMode)mode
{
var panel = [CPColorPanel sharedColorPanel];
[panel setMode: mode];
[panel setMode:mode];
}
/*
@@ -116,7 +118,7 @@ CPColorPickerViewHeight = 370;
*/
- (id)init
{
self = [super initWithContentRect:CGRectMake(500.0, 50.0, 219.0, 370.0)
self = [super initWithContentRect:CGRectMake(500.0, 50.0, 219.0, 370.0)
styleMask:(CPTitledWindowMask | CPClosableWindowMask | CPResizableWindowMask)];
if (self)
@@ -125,14 +127,14 @@ CPColorPickerViewHeight = 370;
[self setTitle:@"Color Panel"];
[self setLevel:CPFloatingWindowLevel];
[self setFloatingPanel:YES];
[self setBecomesKeyOnlyIfNeeded:YES];
[self setMinSize:CGSizeMake(219.0, 342.0)];
[self setMaxSize:CGSizeMake(323.0, 537.0)];
}
return self;
}
@@ -143,12 +145,12 @@ CPColorPickerViewHeight = 370;
{
_color = aColor;
[_previewView setBackgroundColor: _color];
[CPApp sendAction:@selector(changeColor:) to:nil from:self];
if (_target && _action)
[CPApp sendAction:_action to:_target from:self];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPColorPanelColorDidChangeNotification
object:self];
@@ -165,7 +167,7 @@ CPColorPickerViewHeight = 370;
- (void)setColor:(CPColor)aColor updatePicker:(BOOL)bool
{
[self setColor:aColor];
if (bool)
[_activePicker setColor:_color];
}
@@ -232,30 +234,30 @@ CPColorPickerViewHeight = 370;
{
var picker = _colorPickers[[sender tag]],
view = [picker provideNewView:NO];
if (!view)
view = [picker provideNewView:YES];
if (view == _currentView)
return;
if (_currentView)
[view setFrame:[_currentView frame]];
else
{
var height = (TOOLBAR_HEIGHT+10+PREVIEW_HEIGHT+5+SWATCH_HEIGHT+32),
var height = (TOOLBAR_HEIGHT + 10 + PREVIEW_HEIGHT + 5 + SWATCH_HEIGHT + 32),
bounds = [[self contentView] bounds];
[view setFrameSize: CPSizeMake(bounds.size.width - 10, bounds.size.height - height)];
[view setFrameOrigin: CPPointMake(5, height)];
[view setFrameSize:CPSizeMake(bounds.size.width - 10, bounds.size.height - height)];
[view setFrameOrigin:CPPointMake(5, height)];
}
[_currentView removeFromSuperview];
[[self contentView] addSubview:view];
_currentView = view;
_activePicker = picker;
[picker setColor:[self color]];
}
@@ -285,7 +287,7 @@ CPColorPickerViewHeight = 370;
_colorPickers = [];
var count = [ColorPickerClasses count];
for (var i=0; i<count; i++)
for (var i = 0; i < count; i++)
{
var currentPickerClass = ColorPickerClasses[i],
currentPicker = [[currentPickerClass alloc] initWithPickerMask:0 colorPanel:self];
@@ -297,29 +299,29 @@ CPColorPickerViewHeight = 370;
bounds = [contentView bounds];
_toolbar = [[CPView alloc] initWithFrame:CGRectMake(0, 6, CGRectGetWidth(bounds), TOOLBAR_HEIGHT)];
[_toolbar setAutoresizingMask: CPViewWidthSizable];
[_toolbar setAutoresizingMask: CPViewWidthSizable];
var totalToolbarWidth = count * ICON_WIDTH + (count - 1) * ICON_PADDING,
leftOffset = (CGRectGetWidth(bounds) - totalToolbarWidth) / 2.0,
buttonForLater = nil;
for (var i=0; i<count; i++)
for (var i = 0; i < count; i++)
{
var image = [_colorPickers[i] provideNewButtonImage],
highlightImage = [_colorPickers[i] provideNewAlternateButtonImage],
button = [[CPButton alloc] initWithFrame:CGRectMake(leftOffset + i*(ICON_WIDTH+ICON_PADDING), 0, ICON_WIDTH, ICON_WIDTH)];
button = [[CPButton alloc] initWithFrame:CGRectMake(leftOffset + i * (ICON_WIDTH + ICON_PADDING), 0, ICON_WIDTH, ICON_WIDTH)];
[button setTag:i];
[button setTarget:self];
[button setAction:@selector(_setPicker:)];
[button setBordered:NO];
[button setAutoresizingMask:CPViewMinXMargin|CPViewMaxXMargin];
[button setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin];
[button setImage:image];
[button setAlternateImage:highlightImage];
[_toolbar addSubview:button];
if (!buttonForLater)
buttonForLater = button;
}
@@ -330,7 +332,7 @@ CPColorPickerViewHeight = 370;
_previewView = [[_CPColorPanelPreview alloc] initWithFrame:CGRectInset([previewBox bounds], 2.0, 2.0)];
[_previewView setColorPanel:self];
[_previewView setAutoresizingMask:CPViewWidthSizable];
[_previewView setAutoresizingMask:CPViewWidthSizable];
[previewBox setBackgroundColor:[CPColor colorWithWhite:0.8 alpha:1.0]];
[previewBox setAutoresizingMask:CPViewWidthSizable];
@@ -338,7 +340,7 @@ CPColorPickerViewHeight = 370;
[previewBox addSubview:_previewView];
var _previewLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + 10, 60, 15)];
[_previewLabel setStringValue: "Preview:"];
[_previewLabel setStringValue:"Preview:"];
[_previewLabel setTextColor:[CPColor blackColor]];
[_previewLabel setAlignment:CPRightTextAlignment];
@@ -350,8 +352,8 @@ CPColorPickerViewHeight = 370;
_swatchView = [[_CPColorPanelSwatches alloc] initWithFrame:CGRectInset([swatchBox bounds], 1.0, 1.0)];
[_swatchView setColorPanel: self];
[_swatchView setAutoresizingMask: CPViewWidthSizable];
[_swatchView setColorPanel:self];
[_swatchView setAutoresizingMask:CPViewWidthSizable];
[swatchBox addSubview:_swatchView];
@@ -367,7 +369,7 @@ CPColorPickerViewHeight = 370;
[opacityLabel setAlignment:CPRightTextAlignment];
_opacitySlider = [[CPSlider alloc] initWithFrame:CGRectMake(76, TOOLBAR_HEIGHT + PREVIEW_HEIGHT + 34, CGRectGetWidth(bounds) - 86, 20.0)];
[_opacitySlider setMinValue:0.0];
[_opacitySlider setMaxValue:1.0];
@@ -415,37 +417,37 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
CPCookie _swatchCookie;
}
-(id)initWithFrame:(CPRect)aFrame
- (id)initWithFrame:(CPRect)aFrame
{
self = [super initWithFrame:aFrame];
[self setBackgroundColor: [CPColor grayColor]];
[self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]];
var whiteColor = [CPColor whiteColor];
_swatchCookie = [[CPCookie alloc] initWithName: CPColorPanelSwatchesCookie];
var colorList = [self startingColorList];
_swatches = [];
for(var i=0; i < 50; i++)
for (var i = 0; i < 50; i++)
{
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
var view = [[CPView alloc] initWithFrame: CPRectMake(13*i+1, 1, 12, 12)],
var view = [[CPView alloc] initWithFrame: CPRectMake(13 * i + 1, 1, 12, 12)],
fillView = [[CPView alloc] initWithFrame:CGRectInset([view bounds], 1.0, 1.0)];
[view setBackgroundColor:whiteColor];
[fillView setBackgroundColor: (i < colorList.length) ? colorList[i] : whiteColor];
[view addSubview:fillView];
[self addSubview: view];
_swatches.push(view);
}
return self;
}
@@ -457,7 +459,8 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (CPArray)startingColorList
{
var cookieValue = [_swatchCookie value];
if(cookieValue == "")
if (cookieValue == "")
{
return [
[CPColor blackColor],
@@ -471,11 +474,11 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
[CPColor yellowColor]
];
}
var cookieValue = eval(cookieValue);
var result = [];
for(var i=0; i<cookieValue.length; i++)
var cookieValue = eval(cookieValue),
result = [];
for (var i = 0; i < cookieValue.length; i++)
result.push([CPColor colorWithHexString: cookieValue[i]]);
return result;
@@ -485,12 +488,12 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{
var result = [];
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
for(var i=0; i<_swatches.length; i++)
for (var i = 0; i < _swatches.length; i++)
result.push([[[_swatches[i] subviews][0] backgroundColor] hexString]);
var future = new Date();
future.setYear(2019);
[_swatchCookie setValue: JSON.stringify(result) expires:future domain: nil];
}
@@ -520,8 +523,8 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
bounds = [self bounds];
if(!CGRectContainsPoint(bounds, point) || point.x > [self bounds].size.width - 1 || point.x < 1)
if (!CGRectContainsPoint(bounds, point) || point.x > [self bounds].size.width - 1 || point.x < 1)
return NO;
[_colorPanel setColor: [self colorAtIndex:FLOOR(point.x / 13)] updatePicker: YES];
@@ -535,21 +538,21 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
return NO;
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPArray arrayWithObject:CPColorDragType] owner:self];
var swatch = _swatches[FLOOR(point.x / 13)];
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
_dragColor = [[swatch subviews][0] backgroundColor];
var bounds = CPRectCreateCopy([swatch bounds]);
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
var dragView = [[CPView alloc] initWithFrame: bounds];
var dragView = [[CPView alloc] initWithFrame: bounds],
dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
[dragView setBackgroundColor:[CPColor blackColor]];
[dragFillView setBackgroundColor:_dragColor];
[dragView addSubview:dragFillView];
[self dragView: dragView
@@ -563,19 +566,19 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{
if(aType == CPColorDragType)
if (aType == CPColorDragType)
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:_dragColor] forType:aType];
}
- (void)performDragOperation:(id <CPDraggingInfo>)aSender
{
{
var location = [self convertPoint:[aSender draggingLocation] fromView:nil],
pasteboard = [aSender draggingPasteboard],
swatch = nil;
if(![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
if (![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
return NO;
[self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex: FLOOR(location.x / 13)];
}
@@ -590,9 +593,9 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (id)initWithFrame:(CPRect)aFrame
{
self = [super initWithFrame:aFrame];
[self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]];
return self;
}
@@ -610,9 +613,9 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{
var pasteboard = [aSender draggingPasteboard];
if(![pasteboard availableTypeFromArray:[CPColorDragType]])
if (![pasteboard availableTypeFromArray:[CPColorDragType]])
return NO;
var color = [CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]];
[_colorPanel setColor:color updatePicker:YES];
}
@@ -626,19 +629,19 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
var bounds = CPRectMake(0, 0, 15, 15);
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
var dragView = [[CPView alloc] initWithFrame: bounds];
var dragView = [[CPView alloc] initWithFrame: bounds],
dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
[dragView setBackgroundColor:[CPColor blackColor]];
[dragFillView setBackgroundColor:[self backgroundColor]];
[dragView addSubview:dragFillView];
[self dragView: dragView
at: CPPointMake(point.x - bounds.size.width / 2.0, point.y - bounds.size.height / 2.0)
offset: CPPointMake(0.0, 0.0)
@@ -650,7 +653,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{
if(aType == CPColorDragType)
if (aType == CPColorDragType)
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:[self backgroundColor]] forType:aType];
}
+36 -39
View File
@@ -21,11 +21,11 @@
*/
@import <Foundation/CPObject.j>
@import "CPColorPanel.j"
#include "Platform/Platform.h"
@import "CPView.j"
/*!
/*!
@ingroup appkit
@class CPColorPicker
@@ -102,18 +102,18 @@
CPColor _cachedColor;
}
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
{
return [super initWithPickerMask:mask colorPanel: owningColorPanel];
}
-(id)initView
- (id)initView
{
aFrame = CPRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
_pickerView = [[CPView alloc] initWithFrame:aFrame];
[_pickerView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_pickerView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
_brightnessSlider = [[CPSlider alloc] initWithFrame:CGRectMake(0, (aFrame.size.height - 34), aFrame.size.width, 15)];
@@ -136,17 +136,17 @@
[_pickerView addSubview:_brightnessSlider];
}
-(void)brightnessSliderDidChange:(id)sender
- (void)brightnessSliderDidChange:(id)sender
{
[self updateColor];
}
-(void)colorWheelDidChange:(id)sender
- (void)colorWheelDidChange:(id)sender
{
[self updateColor];
}
-(void)updateColor
- (void)updateColor
{
var hue = [_hueSaturationView angle],
saturation = [_hueSaturationView distance],
@@ -223,7 +223,7 @@
float _radius;
}
-(id)initWithFrame:(CPRect)aFrame
- (id)initWithFrame:(CPRect)aFrame
{
self = [super initWithFrame:aFrame];
@@ -261,19 +261,19 @@
return self;
}
-(void)setWheelBrightness:(float)brightness
- (void)setWheelBrightness:(float)brightness
{
_blackWheelImage.style.opacity = 1.0 - brightness;
_blackWheelImage.style.filter = "alpha(opacity=" + (1.0 - brightness)*100 + ")"
_blackWheelImage.style.filter = "alpha(opacity=" + (1.0 - brightness) * 100 + ")"
}
-(void)setFrameSize:(CPSize)aSize
- (void)setFrameSize:(CPSize)aSize
{
[super setFrameSize:aSize];
[self setWheelSize:aSize];
}
-(void)setWheelSize:(CPSize)aSize
- (void)setWheelSize:(CPSize)aSize
{
var min = MIN(aSize.width, aSize.height);
@@ -296,57 +296,55 @@
[self setAngle:[self degreesToRadians:_angle] distance:(_distance / 100.0) * _radius];
}
-(void)setDelegate:(id)aDelegate
- (void)setDelegate:(id)aDelegate
{
_delegate = aDelegate;
}
-(id)delegate
- (id)delegate
{
return _delegate;
}
-(float)angle
- (float)angle
{
return _angle;
}
-(float)distance
- (float)distance
{
return _distance;
}
-(void)mouseDown:(CPEvent)anEvent
- (void)mouseDown:(CPEvent)anEvent
{
[self reposition:anEvent];
}
-(void)mouseDragged:(CPEvent)anEvent
- (void)mouseDragged:(CPEvent)anEvent
{
[self reposition:anEvent];
}
-(void)reposition:(CPEvent)anEvent
- (void)reposition:(CPEvent)anEvent
{
var bounds = [self bounds],
location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
var midX = CGRectGetMidX(bounds);
var midY = CGRectGetMidY(bounds);
var distance = MIN(SQRT((location.x - midX)*(location.x - midX) + (location.y - midY)*(location.y - midY)), _radius);
var angle = ATAN2(location.y - midY, location.x - midX);
location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
midX = CGRectGetMidX(bounds),
midY = CGRectGetMidY(bounds),
distance = MIN(SQRT((location.x - midX) * (location.x - midX) + (location.y - midY) * (location.y - midY)), _radius),
angle = ATAN2(location.y - midY, location.x - midX);
[self setAngle:angle distance:distance];
[_delegate colorWheelDidChange:self];
}
-(void)setAngle:(int)angle distance:(float)distance
- (void)setAngle:(int)angle distance:(float)distance
{
var bounds = [self bounds];
var midX = CGRectGetMidX(bounds);
var midY = CGRectGetMidY(bounds);
var bounds = [self bounds],
midX = CGRectGetMidX(bounds),
midY = CGRectGetMidY(bounds);
_angle = [self radiansToDegrees:angle];
_distance = (distance / _radius) * 100.0;
@@ -354,23 +352,22 @@
[_crosshair setFrameOrigin:CPPointMake(COS(angle) * distance + midX - 2.0, SIN(angle) * distance + midY - 2.0)];
}
-(void)setPositionToColor:(CPColor)aColor
- (void)setPositionToColor:(CPColor)aColor
{
var hsb = [aColor hsbComponents],
bounds = [self bounds];
var angle = [self degreesToRadians:hsb[0]],
bounds = [self bounds],
angle = [self degreesToRadians:hsb[0]],
distance = (hsb[1] / 100.0) * _radius;
[self setAngle:angle distance:distance];
}
-(int)radiansToDegrees:(float)radians
- (int)radiansToDegrees:(float)radians
{
return ((-radians / PI) * 180 + 360) % 360;
}
-(float)degreesToRadians:(float)degrees
- (float)degreesToRadians:(float)degrees
{
return -(((degrees - 360) / 180) * PI);
}
+36 -30
View File
@@ -29,7 +29,7 @@
var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiveNotification";
/*!
/*!
@ingroup appkit
@class CPColorWell
@@ -41,7 +41,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{
BOOL _active;
BOOL _bordered;
CPColor _color;
CPView _wellView;
}
@@ -49,19 +49,19 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_active = NO;
_bordered = YES;
_color = [CPColor whiteColor];
[self drawBezelWithHighlight:NO];
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
[self _registerForNotifications];
}
return self;
}
@@ -97,9 +97,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{
if (_bordered == bordered)
return;
_bordered = bordered;
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
}
@@ -120,9 +120,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{
if (_color == aColor)
return;
_color = aColor;
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
}
@@ -137,7 +137,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
// Activating and Deactivating Color Wells
/*!
Activates the color well, displays the color panel, and makes the panel's current color the same as its own.
Activates the color well, displays the color panel, and makes the panel's current color the same as its own.
If exclusive is \c YES, deactivates any other CPColorWells. \c NO, keeps them active.
@param shouldBeExclusive whether other color wells should be deactivated.
*/
@@ -152,9 +152,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
if ([self isActive])
return;
_active = YES;
[[CPNotificationCenter defaultCenter]
addObserver:self
selector:@selector(colorPanelDidChangeColor:)
@@ -169,9 +169,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{
if (![self isActive])
return;
_active = NO;
[[CPNotificationCenter defaultCenter]
removeObserver:self
name:CPColorPanelColorDidChangeNotification
@@ -202,19 +202,19 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{
_wellView = [[CPView alloc] initWithFrame:aRect];
[_wellView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[self addSubview:_wellView];
}
else
[_wellView setFrame:aRect];
[_wellView setBackgroundColor:_color];
}
- (void)colorPanelDidChangeColor:(CPNotification)aNotification
{
[self takeColorFrom:[aNotification object]];
[self sendAction:[self action] to:[self target]];
}
@@ -231,25 +231,31 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
- (void)mouseDown:(CPEvent)anEvent
{
if (![self isEnabled])
return;
[self drawBezelWithHighlight:YES];
}
- (void)mouseDragged:(CPEvent)anEvent
{
if (![self isEnabled])
return;
[self drawBezelWithHighlight:CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil])];
}
-(void)mouseUp:(CPEvent)anEvent
- (void)mouseUp:(CPEvent)anEvent
{
[self drawBezelWithHighlight:NO];
if (!CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil]))
if (!CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil]) || ![self isEnabled])
return;
[self activate:YES];
var colorPanel = [CPColorPanel sharedColorPanel];
[colorPanel setColor:_color];
[colorPanel orderFront:self];
}
@@ -268,11 +274,11 @@ var CPColorWellColorKey = "CPColorWellColorKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
_active = NO;
_bordered = [aCoder decodeObjectForKey:CPColorWellBorderedKey];
_bordered = [aCoder decodeBoolForKey:CPColorWellBorderedKey];
_color = [aCoder decodeObjectForKey:CPColorWellColorKey];
[self drawBezelWithHighlight:NO];
@@ -280,7 +286,7 @@ var CPColorWellColorKey = "CPColorWellColorKey",
[self _registerForNotifications];
}
return self;
}
@@ -290,17 +296,17 @@ var CPColorWellColorKey = "CPColorWellColorKey",
*/
- (void)encodeWithCoder:(CPCoder)aCoder
{
// We do this in order to avoid encoding the _wellView, which
// We do this in order to avoid encoding the _wellView, which
// should just automatically be created programmatically as needed.
var actualSubviews = _subviews;
_subviews = [_subviews copy];
[_subviews removeObjectIdenticalTo:_wellView];
[super encodeWithCoder:aCoder];
_subviews = actualSubviews;
[aCoder encodeObject:_color forKey:CPColorWellColorKey];
[aCoder encodeObject:_bordered forKey:CPColorWellBorderedKey];
}
+17 -18
View File
@@ -23,6 +23,7 @@
@import "CPEvent.j"
@import "CPPlatform.j"
// Browser Engines
CPUnknownBrowserEngine = 0;
CPGeckoBrowserEngine = 1;
@@ -65,8 +66,6 @@ CPInputTypeCanBeChangedFeature = 1 << 25;
CPHTML5DragAndDropSourceYOffBy1 = 1 << 26;
var USER_AGENT = "",
PLATFORM_ENGINE = CPUnknownBrowserEngine,
PLATFORM_FEATURES = 0;
@@ -75,27 +74,27 @@ var USER_AGENT = "",
PLATFORM_FEATURES |= CPInputTypeCanBeChangedFeature;
if (typeof window != "undfined" && typeof window.navigator != "undefined")
if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
USER_AGENT = window.navigator.userAgent;
// Opera
if (window.opera)
if (typeof window !== "undefined" && window.opera)
{
PLATFORM_ENGINE = CPOperaBrowserEngine;
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
}
// Internet Explorer
else if (window.attachEvent) // Must follow Opera check.
else if (typeof window !== "undefined" && window.attachEvent) // Must follow Opera check.
{
PLATFORM_ENGINE = CPInternetExplorerBrowserEngine;
// Features we can only be sure of with IE (no known independent tests)
PLATFORM_FEATURES |= CPVMLFeature;
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
PLATFORM_FEATURES |= CPOpacityRequiresFilterFeature;
PLATFORM_FEATURES &= ~CPInputTypeCanBeChangedFeature;
@@ -105,7 +104,7 @@ else if (window.attachEvent) // Must follow Opera check.
else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
{
PLATFORM_ENGINE = CPWebKitBrowserEngine;
// Features we can only be sure of with WebKit (no known independent tests)
PLATFORM_FEATURES |= CPCSSRGBAFeature;
PLATFORM_FEATURES |= CPHTMLContentEditableFeature;
@@ -116,7 +115,7 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
PLATFORM_FEATURES |= CPJavascriptClipboardEventsFeature;
PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature;
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length,
versionEnd = USER_AGENT.indexOf(" ", versionStart),
versionString = USER_AGENT.substring(versionStart, versionEnd),
@@ -124,7 +123,7 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
majorVersion = parseInt(versionString.substring(0, versionDivision)),
minorVersion = parseInt(versionString.substr(versionDivision + 1));
if((USER_AGENT.indexOf("Safari") !== CPNotFound && (majorVersion > 525 || (majorVersion === 525 && minorVersion > 14))) || USER_AGENT.indexOf("Chrome") !== CPNotFound)
if ((USER_AGENT.indexOf("Safari") !== CPNotFound && (majorVersion > 525 || (majorVersion === 525 && minorVersion > 14))) || USER_AGENT.indexOf("Chrome") !== CPNotFound)
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
// FIXME this is a terrible hack to get around this bug:
@@ -146,12 +145,12 @@ else if (USER_AGENT.indexOf("KHTML") != -1) // Must follow WebKit check.
else if (USER_AGENT.indexOf("Gecko") !== -1) // Must follow KHTML check.
{
PLATFORM_ENGINE = CPGeckoBrowserEngine;
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
var index = USER_AGENT.indexOf("Firefox"),
version = (index === -1) ? 2.0 : parseFloat(USER_AGENT.substring(index + "Firefox".length + 1));
if (version >= 3.0)
PLATFORM_FEATURES |= CPCSSRGBAFeature;
@@ -167,16 +166,16 @@ if (typeof document != "undefined")
if (canvasElement && canvasElement.getContext)
{
PLATFORM_FEATURES |= CPHTMLCanvasFeature;
// Detect Canvas setTransform/transform support
var context = document.createElement("canvas").getContext("2d");
if (context && context.setTransform && context.transform)
PLATFORM_FEATURES |= CPJavaScriptCanvasTransformFeature;
}
var DOMElement = document.createElement("div");
// Detect whether we have innerText or textContent (or neither)
if (DOMElement.innerText != undefined)
PLATFORM_FEATURES |= CPJavascriptInnerTextFeature;
+176 -64
View File
@@ -23,9 +23,8 @@
@import "CPFont.j"
@import "CPShadow.j"
@import "CPView.j"
@import "CPKeyValueBinding.j"
#include "CoreGraphics/CGGeometry.h"
#include "Platform/Platform.h"
CPLeftTextAlignment = 0;
CPRightTextAlignment = 1;
@@ -75,7 +74,7 @@ CPControlTextDidEndEditingNotification = "CPControlTextDidEndEditingNotific
var CPControlBlackColor = [CPColor blackColor];
/*!
/*!
@ingroup appkit
@class CPControl
@@ -84,7 +83,7 @@ var CPControlBlackColor = [CPColor blackColor];
@implementation CPControl : CPView
{
id _value;
// Target-Action Support
id _target;
SEL _action;
@@ -126,16 +125,46 @@ var CPControlBlackColor = [CPColor blackColor];
@"max-size"]];
}
+ (void)initialize
{
if (self === [CPControl class])
{
[self exposeBinding:@"value"];
[self exposeBinding:@"objectValue"];
[self exposeBinding:@"stringValue"];
[self exposeBinding:@"integerValue"];
[self exposeBinding:@"intValue"];
[self exposeBinding:@"doubleValue"];
[self exposeBinding:@"floatValue"];
[self exposeBinding:@"enabled"];
}
}
- (void)_reverseSetBinding
{
var theBinding = [CPKeyValueBinding getBinding:CPValueBinding forObject:self];
[theBinding reverseSetValueFor:@"objectValue"];
}
- (void)_replacementKeyPathForBinding:(CPString)aBinding
{
if (aBinding === @"value")
return @"objectValue";
return [super _replacementKeyPathForBinding:aBinding];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_sendActionOn = CPLeftMouseUpMask;
_trackingMouseDownFlags = 0;
}
return self;
}
@@ -180,15 +209,16 @@ var CPControlBlackColor = [CPColor blackColor];
*/
- (void)sendAction:(SEL)anAction to:(id)anObject
{
[self _reverseSetBinding];
[CPApp sendAction:anAction to:anObject from:self];
}
- (int)sendActionOn:(int)mask
{
var previousMask = _sendActionOn;
_sendActionOn = mask;
return previousMask;
}
@@ -201,7 +231,7 @@ var CPControlBlackColor = [CPColor blackColor];
{
if (_toolTip == aToolTip)
return;
_toolTip = aToolTip;
#if PLATFORM(DOM)
@@ -236,7 +266,7 @@ var CPControlBlackColor = [CPColor blackColor];
// Some subclasses should redefine this with CPLeftMouseDraggedMask
if (flag)
_sendActionOn |= CPPeriodicMask;
else
else
_sendActionOn &= ~CPPeriodicMask;
}
@@ -248,16 +278,15 @@ var CPControlBlackColor = [CPColor blackColor];
- (void)trackMouse:(CPEvent)anEvent
{
var type = [anEvent type],
currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil];
currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil],
isWithinFrame = [self tracksMouseOutsideOfFrame] || CGRectContainsPoint([self bounds], currentLocation);
if (type === CPLeftMouseUp)
{
[self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:YES];
_trackingMouseDownFlags = 0;
}
else
{
if (type === CPLeftMouseDown)
@@ -271,20 +300,20 @@ var CPControlBlackColor = [CPColor blackColor];
{
if (!_trackingWasWithinFrame)
_continuousTracking = [self startTrackingAt:currentLocation];
else if (_continuousTracking)
_continuousTracking = [self continueTracking:_previousTrackingLocation at:currentLocation];
}
else
[self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:NO];
}
[CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
if ((_sendActionOn & (1 << type)) && isWithinFrame)
[self sendAction:_action to:_target];
_trackingWasWithinFrame = isWithinFrame;
_previousTrackingLocation = currentLocation;
}
@@ -298,13 +327,26 @@ var CPControlBlackColor = [CPColor blackColor];
return 0;
}
- (void)performClick:(id)sender
- (void)performClick:(id)sender
{
if (![self isEnabled])
return;
[self highlight:YES];
[self setState:[self nextState]];
[self sendAction:[self action] to:[self target]];
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
try
{
[self sendAction:[self action] to:[self target]];
}
catch (e)
{
throw e;
}
finally
{
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
}
}
- (void)unhighlightButtonTimerDidFinish:(id)sender
@@ -320,7 +362,7 @@ var CPControlBlackColor = [CPColor blackColor];
- (BOOL)startTrackingAt:(CGPoint)aPoint
{
[self highlight:YES];
return (_sendActionOn & CPPeriodicMask) || (_sendActionOn & CPLeftMouseDraggedMask);
}
@@ -338,7 +380,7 @@ var CPControlBlackColor = [CPColor blackColor];
{
if (![self isEnabled])
return;
[self trackMouse:anEvent];
}
@@ -356,7 +398,7 @@ var CPControlBlackColor = [CPColor blackColor];
- (void)setObjectValue:(id)anObject
{
_value = anObject;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
@@ -430,7 +472,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's int value
Returns the receiver's string value
*/
- (CPString)stringValue
{
@@ -438,7 +480,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Set's the receiver's int value
Set's the receiver's string value
*/
- (void)setStringValue:(CPString)anObject
{
@@ -485,54 +527,124 @@ var CPControlBlackColor = [CPColor blackColor];
[self setStringValue:[sender stringValue]];
}
- (void)textDidBeginEditing:(CPNotification)note
- (void)textDidBeginEditing:(CPNotification)note
{
//this looks to prevent false propagation of notifications for other objects
if([note object] != self)
if ([note object] != self)
return;
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidBeginEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
}
- (void)textDidChange:(CPNotification)note
- (void)textDidChange:(CPNotification)note
{
//this looks to prevent false propagation of notifications for other objects
if([note object] != self)
if ([note object] != self)
return;
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidChangeNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
}
- (void)textDidEndEditing:(CPNotification)note
- (void)textDidEndEditing:(CPNotification)note
{
//this looks to prevent false propagation of notifications for other objects
if([note object] != self)
if ([note object] != self)
return;
[self _reverseSetBinding];
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
}
#define BRIDGE(UPPERCASE, LOWERCASE, ATTRIBUTENAME) \
/*! Sets the value for ATTRIBUTENAME */\
- (void)set##UPPERCASE:(id)aValue\
{\
[self setValue:aValue forThemeAttribute:ATTRIBUTENAME];\
}\
/*! Returns the current value for ATTRIBUTENAME */\
- (id)LOWERCASE\
{\
return [self valueForThemeAttribute:ATTRIBUTENAME];\
- (void)setAlignment:(CPTextAlignment)alignment
{
[self setValue:alignment forThemeAttribute:@"alignment"];
}
BRIDGE(Alignment, alignment, "alignment")
BRIDGE(VerticalAlignment, verticalAlignment, "vertical-alignment")
BRIDGE(LineBreakMode, lineBreakMode, "line-break-mode")
BRIDGE(TextColor, textColor, "text-color")
BRIDGE(Font, font, "font")
BRIDGE(TextShadowColor, textShadowColor, "text-shadow-color")
BRIDGE(TextShadowOffset, textShadowOffset, "text-shadow-offset")
BRIDGE(ImagePosition, imagePosition, "image-position")
BRIDGE(ImageScaling, imageScaling, "image-scaling")
- (CPTextAlignment)alignment
{
return [self valueForThemeAttribute:@"alignment"];
}
- (void)setVerticalAlignment:(CPTextVerticalAlignment)alignment
{
[self setValue:alignment forThemeAttribute:@"vertical-alignment"];
}
- (CPTextVerticalAlignment)verticalAlignment
{
return [self valueForThemeAttribute:@"vertical-alignment"];
}
- (void)setLineBreakMode:(CPLineBreakMode)mode
{
[self setValue:mode forThemeAttribute:@"line-break-mode"];
}
- (CPLineBreakMode)lineBreakMode
{
return [self valueForThemeAttribute:@"line-break-mode"];
}
- (void)setTextColor:(CPColor)aColor
{
[self setValue:aColor forThemeAttribute:@"text-color"];
}
- (CPColor)textColor
{
return [self valueForThemeAttribute:@"text-color"];
}
- (void)setTextShadowColor:(CPColor)aColor
{
[self setValue:aColor forThemeAttribute:@"text-shadow-color"];
}
- (CPColor)textShadowColor
{
return [self valueForThemeAttribute:@"text-shadow-color"];
}
- (void)setTextShadowOffset:(float)offset
{
[self setValue:offset forThemeAttribute:@"text-shadow-offset"];
}
- (float)textShadowOffset
{
return [self valueForThemeAttribute:@"text-shadow-offset"];
}
- (void)setFont:(CPFont)aFont
{
[self setValue:aFont forThemeAttribute:@"font"];
}
- (CPFont)font
{
return [self valueForThemeAttribute:@"font"];
}
- (void)setImagePosition:(CPCellImagePosition)position
{
[self setValue:position forThemeAttribute:@"image-position"];
}
- (CPCellImagePosition)imagePosition
{
return [self valueForThemeAttribute:@"image-position"];
}
- (void)setImageScaling:(CPImageScaling)scaling
{
[self setValue:scaling forThemeAttribute:@"image-scaling"];
}
- (CPImageScaling)imageScaling
{
return [self valueForThemeAttribute:@"image-scaling"];
}
- (void)setEnabled:(BOOL)isEnabled
{
@@ -570,7 +682,7 @@ BRIDGE(ImageScaling, imageScaling, "image-scaling")
var CPControlValueKey = "CPControlValueKey",
CPControlControlStateKey = @"CPControlControlStateKey",
CPControlIsEnabledKey = "CPControlIsEnabledKey",
CPControlTargetKey = "CPControlTargetKey",
CPControlActionKey = "CPControlActionKey",
CPControlSendActionOnKey = "CPControlSendActionOnKey",
@@ -600,7 +712,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
[self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]];
[self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]];
}
return self;
}
@@ -636,7 +748,7 @@ var _CPControlSizeIdentifiers = [],
_CPControlSizeIdentifiers[CPRegularControlSize] = "Regular";
_CPControlSizeIdentifiers[CPSmallControlSize] = "Small";
_CPControlSizeIdentifiers[CPMiniControlSize] = "Mini";
function _CPControlIdentifierForControlSize(aControlSize)
{
return _CPControlSizeIdentifiers[aControlSize];
@@ -647,21 +759,21 @@ function _CPControlColorWithPatternImage(sizes, aClassName)
var index = 1,
count = arguments.length,
identifier = "";
for (; index < count; ++index)
identifier += arguments[index];
var color = _CPControlCachedColorWithPatternImages[identifier];
if (!color)
{
var bundle = [CPBundle bundleForClass:[CPControl class]];
color = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:aClassName + "/" + identifier + ".png"] size:sizes[identifier]]];
_CPControlCachedColorWithPatternImages[identifier] = color;
}
return color;
}
@@ -670,17 +782,17 @@ function _CPControlThreePartImagePattern(isVertical, sizes, aClassName)
var index = 2,
count = arguments.length,
identifier = "";
for (; index < count; ++index)
identifier += arguments[index];
var color = _CPControlCachedThreePartImagePattern[identifier];
if (!color)
{
var bundle = [CPBundle bundleForClass:[CPControl class]],
path = aClassName + "/" + identifier;
sizes = sizes[identifier];
color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:[
@@ -688,9 +800,9 @@ function _CPControlThreePartImagePattern(isVertical, sizes, aClassName)
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "1.png"] size:sizes[1]],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "2.png"] size:sizes[2]]
] isVertical:isVertical]];
_CPControlCachedThreePartImagePattern[identifier] = color;
}
return color;
}
+88
View File
@@ -0,0 +1,88 @@
//
// CPController.j
// AppKit
//
// Created by Ross Boucher 1/15/09
// Copyright 280 North
//
// Adapted from GNUStep
// Copyright (C) 2007 Free Software Foundation, Inc
// Released under the LGPL.
//
@import <Foundation/CPObject.j>
var CPControllerDeclaredKeysKey = @"CPControllerDeclaredKeysKey";
@implementation CPController : CPObject
{
CPArray _editors;
CPArray _declaredKeys;
}
- (id)init
{
self = [super init];
if (self)
{
_editors = [];
_declaredKeys = [];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
if ([_declaredKeys count] > 0)
[aCoder encodeObject:_declaredKeys forKey:CPControllerDeclaredKeysKey];
}
- (id)initWithCoder:(CPCoder)aDecoder
{
self = [super init];
if (self)
{
_editors = [];
_declaredKeys = [aDecoder decodeObjectForKey:CPControllerDeclaredKeysKey] || [];
}
return nil;
}
- (BOOL)isEditing
{
return [_editors count] > 0;
}
- (BOOL)commitEditing
{
var index = 0,
count = _editors.length;
for (; index < count; ++index)
if (![[_editors objectAtIndex:i] commitEditing])
return NO;
return YES;
}
- (void)discardEditing
{
[_editors makeObjectsPerformSelector:@selector(discardEditing)];
}
- (void)objectDidBeginEditing:(id)anEditor
{
[_editors addObject:anEditor];
}
- (void)objectDidEndEditing:(id)anEditor
{
[_editors removeObject:anEditor];
}
@end
+29 -20
View File
@@ -24,7 +24,7 @@
@import <Foundation/CPString.j>
/*!
/*!
@ingroup appkit
@class CPCookie
CPCookie is the Cappuccino interface to a web browser cookie. You can set the name
@@ -33,7 +33,7 @@
{
CPString _cookieName;
CPString _cookieValue;
CPString _expires;
}
@@ -44,7 +44,7 @@
- (id)initWithName:(CPString)aName
{
self = [super init];
_cookieName = aName;
_cookieValue = [self _readCookieValue];
@@ -83,30 +83,39 @@
*/
- (void)setValue:(CPString)value expires:(CPDate)date domain:(CPString)domain
{
if(date)
var expires = "; expires="+date.toGMTString();
else
if (date)
var expires = "; expires=" + date.toGMTString();
else
var expires = "";
if(domain)
domain = "; domain="+domain;
else
if (domain)
domain = "; domain=" + domain;
else
domain = "";
document.cookie = _cookieName+"="+value+expires+"; path=/"+domain;
#if PLATFORM(DOM)
document.cookie = _cookieName+"="+value+expires+"; path=/"+domain;
#else
_cookieValue = value;
_expires = expires;
#endif
}
/* @ignore */
- (CPString)_readCookieValue
{
var nameEQ = _cookieName + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return "";
#if PLATFORM(DOM)
var nameEQ = _cookieName + "=",
ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++)
{
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
#endif
return "";
}
@end
+15 -10
View File
@@ -12,7 +12,7 @@ Implemented class methods:
Opera : All except resizeLeftRightCursor resizeUpDownCursor operationNotAllowedCursor dragCopyCursor dragLinkCursor contextualMenuCursor openHandCursor closedHandCursor disappearingItemCursor // Opera does not support url cursors so these won't work with images
*/
#include "Platform/Platform.h"
@import <Foundation/CPObject.j>
var currentCursor = nil,
cursorStack = [],
@@ -61,9 +61,9 @@ var currentCursor = nil,
if (CPBrowserIsEngine(CPGeckoBrowserEngine))
cursorURLFormat += ", default";
}
var url = [CPString stringWithFormat:cursorURLFormat, imageName];
return [[CPCursor alloc] initWithCSSString:url];
}
@@ -96,7 +96,7 @@ var currentCursor = nil,
{
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
return [CPCursor cursorWithCSSString:"s-resize"]; // WebKit | FF | opera
}
@@ -167,18 +167,22 @@ var currentCursor = nil,
{
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
return [CPCursor cursorWithCSSString:@"-webkit-grab"];
else if (CPBrowserIsEngine(CPGeckoBrowserEngine) || CPBrowserIsEngine(CPOperaBrowserEngine))
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
return [CPCursor cursorWithCSSString:@"-moz-grab"];
else if (CPBrowserIsEngine(CPOperaBrowserEngine))
return [CPCursor cursorWithCSSString:@"move"];
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only. move in FFMac|Opera
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only. move in FFMac|Opera
}
+ (CPCursor)closedHandCursor
{
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
return [CPCursor cursorWithCSSString:@"-webkit-grabbing"];
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
return [CPCursor cursorWithCSSString:@"-moz-grabbing"];
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit || FF
}
+ (CPCursor)disappearingItemCursor
@@ -193,7 +197,7 @@ var currentCursor = nil,
+ (void)unhide
{
[self _setCursorCSS:[currentCursor _cssString]]
[self _setCursorCSS:[currentCursor _cssString]];
}
+ (void)setHiddenUntilMouseMoves:(BOOL)flag
@@ -206,9 +210,10 @@ var currentCursor = nil,
- (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot
{
return [self initWithCSSString:"url(" + [image filename] + ")"];
return [self initWithCSSString:"url(" + [image filename] + "), auto"];
}
- (void)mouseEntered:(CPEvent)event
{
}
@@ -219,7 +224,7 @@ var currentCursor = nil,
- (void)set
{
currentCursor = self;
currentCursor = self;
#if PLATFORM(DOM)
[[self class] _setCursorCSS:_cssString];
+53 -52
View File
@@ -23,6 +23,7 @@
@import <Foundation/CPString.j>
@import <Foundation/CPArray.j>
@import "CPApplication.j"
@import "CPResponder.j"
@import "CPSavePanel.j"
@import "CPViewController.j"
@@ -82,7 +83,7 @@ CPDocumentDidFailToSaveNotification = @"CPDocumentDidFailToSaveNotification";
var CPDocumentUntitledCount = 0;
/*!
/*!
@ingroup appkit
@class CPDocument
@@ -120,7 +121,7 @@ var CPDocumentUntitledCount = 0;
- (id)init
{
self = [super init];
if (self)
{
_windowControllers = [];
@@ -131,7 +132,7 @@ var CPDocumentUntitledCount = 0;
[self setNextResponder:CPApp];
}
return self;
}
@@ -144,10 +145,10 @@ var CPDocumentUntitledCount = 0;
- (id)initWithType:(CPString)aType error:({CPError})anError
{
self = [self init];
if (self)
[self setFileType:aType];
return self;
}
@@ -165,7 +166,7 @@ var CPDocumentUntitledCount = 0;
- (id)initWithContentsOfURL:(CPURL)anAbsoluteURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
{
self = [self init];
if (self)
{
[self setFileURL:anAbsoluteURL];
@@ -173,7 +174,7 @@ var CPDocumentUntitledCount = 0;
[self readFromURL:anAbsoluteURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
}
return self;
}
@@ -190,7 +191,7 @@ var CPDocumentUntitledCount = 0;
- (id)initForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
{
self = [self init];
if (self)
{
[self setFileURL:anAbsoluteURL];
@@ -198,7 +199,7 @@ var CPDocumentUntitledCount = 0;
[self readFromURL:absoluteContentsURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
}
return self;
}
@@ -281,7 +282,7 @@ var CPDocumentUntitledCount = 0;
{
var view = [viewController view],
viewFrame = [view frame];
viewFrame.origin = CGPointMake(50, 50);
var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
@@ -381,14 +382,14 @@ var CPDocumentUntitledCount = 0;
{
if (_fileURL)
return [_fileURL lastPathComponent];
if (!_untitledDocumentIndex)
_untitledDocumentIndex = ++CPDocumentUntitledCount;
if (_untitledDocumentIndex == 1)
return @"Untitled";
return @"Untitled " + _untitledDocumentIndex;
if (_untitledDocumentIndex == 1)
return @"Untitled";
return @"Untitled " + _untitledDocumentIndex;
}
- (CPString)viewCibName
@@ -457,7 +458,7 @@ var CPDocumentUntitledCount = 0;
return;
_fileURL = aFileURL;
[_windowControllers makeObjectsPerformSelector:@selector(synchronizeWindowTitleWithDocumentName)];
}
@@ -488,10 +489,10 @@ var CPDocumentUntitledCount = 0;
[_writeRequest setValue:@"close" forHTTPHeaderField:@"Connection"];
if (aSaveOperation == CPSaveOperation)
if (aSaveOperation === CPSaveOperation)
[_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"];
if (aSaveOperation != CPSaveToOperation)
if (aSaveOperation !== CPSaveToOperation)
[self updateChangeCount:CPChangeCleared];
// FIXME: Oh man is this every looking for trouble, we need to handle login at the Cappuccino level, with HTTP Errors.
@@ -509,21 +510,21 @@ var CPDocumentUntitledCount = 0;
// If we got this far and it wasn't an HTTP request, then everything is fine.
if (![aResponse isKindOfClass:[CPHTTPURLResponse class]])
return;
var statusCode = [aResponse statusCode];
// Nothing to do if everything is hunky dory.
if (statusCode === 200)
return;
var session = aConnection.session;
if (aConnection == _readConnection)
{
[aConnection cancel];
alert("There was an error retrieving the document.");
objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
}
else
@@ -532,23 +533,23 @@ var CPDocumentUntitledCount = 0;
if (statusCode == 409)
{
[aConnection cancel];
if (confirm("There already exists a file with that name, would you like to overwrite it?"))
{
[_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"];
[aConnection start];
}
else
else
{
if (session.saveOperation != CPSaveToOperation)
{
_changeCount += session.changeCount;
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
}
_writeRequest = nil;
objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
[self _sendDocumentSavedNotification:NO];
}
@@ -563,7 +564,7 @@ var CPDocumentUntitledCount = 0;
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)aData
{
var session = aConnection.session;
// READ
if (aConnection == _readConnection)
{
@@ -575,9 +576,9 @@ var CPDocumentUntitledCount = 0;
{
if (session.saveOperation != CPSaveToOperation)
[self setFileURL:session.absoluteURL];
_writeRequest = nil;
objj_msgSend(session.delegate, session.didSaveSelector, self, YES, session.contextInfo);
[self _sendDocumentSavedNotification:YES];
}
@@ -590,17 +591,17 @@ var CPDocumentUntitledCount = 0;
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
{
var session = aConnection.session;
if (_readConnection == aConnection)
objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
else
{
{
if (session.saveOperation != CPSaveToOperation)
{
_changeCount += session.changeCount;
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
}
}
_writeRequest = nil;
@@ -643,9 +644,9 @@ var CPDocumentUntitledCount = 0;
else if (aChangeType == CPChangeCleared)
_changeCount = 0;
/*else if (aChangeType == CPCHangeReadOtherContents)
else if (aChangeType == CPChangeAutosaved)*/
else if (aChangeType == CPChangeAutosaved)*/
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
}
@@ -685,9 +686,9 @@ var CPDocumentUntitledCount = 0;
{
if (_hasUndoManager == aFlag)
return;
_hasUndoManager = aFlag;
if (!_hasUndoManager)
[self setUndoManager:nil];
}
@@ -696,7 +697,7 @@ var CPDocumentUntitledCount = 0;
- (void)_undoManagerWillCloseGroup:(CPNotification)aNotification
{
var undoManager = [aNotification object];
if ([undoManager isUndoing] || [undoManager isRedoing])
return;
@@ -723,13 +724,13 @@ var CPDocumentUntitledCount = 0;
- (void)setUndoManager:(CPUndoManager)anUndoManager
{
var defaultCenter = [CPNotificationCenter defaultCenter];
if (_undoManager)
{
[defaultCenter removeObserver:self
name:CPUndoManagerDidUndoChangeNotification
object:_undoManager];
[defaultCenter removeObserver:self
name:CPUndoManagerDidRedoChangeNotification
object:_undoManager];
@@ -738,17 +739,17 @@ var CPDocumentUntitledCount = 0;
name:CPUndoManagerWillCloseUndoGroupNotification
object:_undoManager];
}
_undoManager = anUndoManager;
if (_undoManager)
{
[defaultCenter addObserver:self
selector:@selector(_undoManagerDidUndoChange:)
name:CPUndoManagerDidUndoChangeNotification
object:_undoManager];
[defaultCenter addObserver:self
selector:@selector(_undoManagerDidRedoChange:)
name:CPUndoManagerDidRedoChangeNotification
@@ -774,7 +775,7 @@ var CPDocumentUntitledCount = 0;
return _undoManager;
}
/*
Implemented as a delegate of a CPWindow
@ignore
@@ -803,7 +804,7 @@ var CPDocumentUntitledCount = 0;
[[CPNotificationCenter defaultCenter]
postNotificationName:CPDocumentWillSaveNotification
object:self];
[self saveToURL:_fileURL ofType:[self fileType] forSaveOperation:CPSaveOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
}
else
@@ -861,7 +862,7 @@ var CPDocumentUntitledCount = 0;
[[CPDocumentController sharedDocumentController] removeDocument:self];
}
- (void)shouldCloseWindowController:(CPWindowController)controller delegate:(id)delegate shouldCloseSelector:(SEL)selector contextInfo:(Object)info
- (void)shouldCloseWindowController:(CPWindowController)controller delegate:(id)delegate shouldCloseSelector:(SEL)selector contextInfo:(Object)info
{
if ([controller shouldCloseDocument] || ([_windowControllers count] < 2 && [_windowControllers indexOfObject:controller] !== CPNotFound))
[self canCloseDocumentWithDelegate:self shouldCloseSelector:@selector(_document:shouldClose:context:) contextInfo:{delegate:delegate, selector:selector, context:info}];
@@ -878,7 +879,7 @@ var CPDocumentUntitledCount = 0;
objj_msgSend(context.delegate, context.selector, aDocument, shouldClose, context.context);
}
- (void)canCloseDocumentWithDelegate:(id)aDelegate shouldCloseSelector:(SEL)aSelector contextInfo:(Object)context
- (void)canCloseDocumentWithDelegate:(id)aDelegate shouldCloseSelector:(SEL)aSelector contextInfo:(Object)context
{
if (![self isDocumentEdited])
return [aDelegate respondsToSelector:aSelector] && objj_msgSend(aDelegate, aSelector, self, YES, context);
+22 -22
View File
@@ -29,7 +29,7 @@
var CPSharedDocumentController = nil;
/*!
/*!
@ingroup appkit
@class CPDocumentController
This class is responsible for managing an application's open documents.
@@ -41,7 +41,7 @@ var CPSharedDocumentController = nil;
}
/*!
Returns the singleton instance of the application's document controller. If it has not
Returns the singleton instance of the application's document controller. If it has not
been created yet, it will be created then returned.
@return a CPDocumentController
*/
@@ -49,7 +49,7 @@ var CPSharedDocumentController = nil;
{
if (!CPSharedDocumentController)
[[self alloc] init];
return CPSharedDocumentController;
}
@@ -59,11 +59,11 @@ var CPSharedDocumentController = nil;
- (id)init
{
self = [super init];
if (self)
{
_documents = [[CPArray alloc] init];
if (!CPSharedDocumentController)
CPSharedDocumentController = self;
@@ -85,16 +85,16 @@ var CPSharedDocumentController = nil;
{
var index = 0,
count = [_documents count];
for (; index < count; ++index)
for (; index < count; ++index)
{
var theDocument = _documents[index];
if ([[theDocument fileURL] isEqual:aURL])
return theDocument;
if ([[theDocument fileURL] isEqual:aURL])
return theDocument;
}
return nil;
return nil;
}
/*!
@@ -105,10 +105,10 @@ var CPSharedDocumentController = nil;
- (void)openUntitledDocumentOfType:(CPString)aType display:(BOOL)shouldDisplay
{
var theDocument = [self makeUntitledDocumentOfType:aType error:nil];
if (theDocument)
[self addDocument:theDocument];
if (shouldDisplay)
{
[theDocument makeWindowControllers];
@@ -210,7 +210,7 @@ var CPSharedDocumentController = nil;
return;
[aDocument makeWindowControllers];
if ([aContextInfo objectForKey:@"shouldDisplay"])
[aDocument showWindows];
}
@@ -224,7 +224,7 @@ var CPSharedDocumentController = nil;
[self openUntitledDocumentOfType:[[_documentTypes objectAtIndex:0] objectForKey:@"CPBundleTypeName"] display:YES];
}
-(void)openDocument:(id)aSender
- (void)openDocument:(id)aSender
{
var openPanel = [CPOpenPanel openPanel];
@@ -276,17 +276,17 @@ var CPSharedDocumentController = nil;
{
var index = 0,
count = _documentTypes.length,
extension = [[anAbsoluteURL pathExtension] lowercaseString],
starType = nil;
for (; index < count; ++index)
{
var documentType = _documentTypes[index],
extensions = [documentType objectForKey:@"CFBundleTypeExtensions"],
extensionIndex = 0,
extensionCount = extensions.length;
for (; extensionIndex < extensionCount; ++extensionIndex)
{
var thisExtension = [extensions[extensionIndex] lowercaseString];
@@ -312,11 +312,11 @@ var CPSharedDocumentController = nil;
for (;i < count; ++i)
{
var documentType = _documentTypes[i];
if ([documentType objectForKey:@"CPBundleTypeName"] == aType)
return documentType;
}
return nil;
}
@@ -336,7 +336,7 @@ var CPSharedDocumentController = nil;
@implementation CPDocumentController (Closing)
- (void)closeAllDocumentsWithDelegate:(id)aDelegate didCloseAllSelector:(SEL)didCloseSelector contextInfo:(Object)info
- (void)closeAllDocumentsWithDelegate:(id)aDelegate didCloseAllSelector:(SEL)didCloseSelector contextInfo:(Object)info
{
var context = {
delegate: aDelegate,
+104 -42
View File
@@ -20,13 +20,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <AppKit/CPView.j>
@import <AppKit/CPEvent.j>
@import <AppKit/CPPasteboard.j>
@import <AppKit/CPImageView.j>
#import "CoreGraphics/CGGeometry.h"
#import "Platform/Platform.h"
@import "CPApplication.j"
@import "CPEvent.j"
@import "CPImageView.j"
@import "CPPasteboard.j"
@import "CPView.j"
@import "CPWindow.j"
CPDragOperationNone = 0,
@@ -40,29 +39,10 @@ CPDragOperationEvery = -1;
#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
var CPDragServerPreviousEvent = nil,
CPDragServerAutoscrollInterval = nil;
/*
var CPDragServerAutoscroll = function()
{
[CPDragServerSource autoscroll:CPDragServerPreviousEvent];
}
var CPDragServerPreviousEvent = nil,
CPDragServerPeriodicUpdateInterval = 0.05;
if (CPDragServerAutoscrollInterval === nil)
{
if ([CPDragServerSource respondsToSelector:@selector(autoscroll:)])
CPDragServerAutoscrollInterval = setInterval(CPDragServerAutoscroll, 100);
}
CPDragServerPreviousEvent = anEvent;
if (CPDragServerAutoscrollInterval !== nil)
clearInterval(CPDragServerAutoscrollInterval);
CPDragServerAutoscrollInterval = nil;
*/
var CPSharedDragServer = nil;
var CPSharedDragServer = nil;
var CPDragServerSource = nil;
var CPDragServerDraggingInfo = nil;
@@ -127,7 +107,7 @@ var CPDragServerDraggingInfo = nil;
@end
var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
CPDraggingSource_draggedImage_endAt_operation_ = 1 << 1,
CPDraggingSource_draggedImage_endedAt_operation_ = 1 << 1,
CPDraggingSource_draggedView_movedTo_ = 1 << 2,
CPDraggingSource_draggedView_endedAt_operation_ = 1 << 3;
@@ -150,10 +130,13 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
CGPoint _draggingLocation;
id _draggingDestination;
BOOL _draggingDestinationWantsPeriodicUpdates;
CGPoint _startDragLocation;
BOOL _shouldSlideBack;
unsigned _dragOperation;
CPTimer _draggingUpdateTimer;
}
/*
@@ -234,6 +217,9 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
- (CPDragOperation)draggingUpdatedInPlatformWindow:(CPPlatformWindow)aPlatformWindow location:(CGPoint)aLocation
{
[_draggingUpdateTimer invalidate];
_draggingUpdateTimer = nil;
var dragOperation = CPDragOperationCopy;
// We have to convert base to bridge since the drag event comes from the source window, not the drag window.
var draggingDestination = [aPlatformWindow _dragHitTest:aLocation pasteboard:[CPDragServerDraggingInfo draggingPasteboard]];
@@ -243,31 +229,95 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
if(draggingDestination !== _draggingDestination)
{
if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingExited:)])
if ([_draggingDestination respondsToSelector:@selector(draggingExited:)])
[_draggingDestination draggingExited:CPDragServerDraggingInfo];
_draggingDestination = draggingDestination;
if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingEntered:)])
if ([_draggingDestination respondsToSelector:@selector(wantsPeriodicDraggingUpdates)])
_draggingDestinationWantsPeriodicUpdates = [_draggingDestination wantsPeriodicDraggingUpdates];
else
_draggingDestinationWantsPeriodicUpdates = YES;
if ([_draggingDestination respondsToSelector:@selector(draggingEntered:)])
dragOperation = [_draggingDestination draggingEntered:CPDragServerDraggingInfo];
}
else if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingUpdated:)])
else if ([_draggingDestination respondsToSelector:@selector(draggingUpdated:)])
dragOperation = [_draggingDestination draggingUpdated:CPDragServerDraggingInfo];
if (!_draggingDestination)
dragOperation = CPDragOperationNone;
else
{
if (_draggingDestinationWantsPeriodicUpdates)
_draggingUpdateTimer = [CPTimer scheduledTimerWithTimeInterval:CPDragServerPeriodicUpdateInterval
target:self
selector:@selector(_sendPeriodicDraggingUpdate:)
userInfo:[CPDictionary dictionaryWithJSObject:{platformWindow:aPlatformWindow, location:aLocation}]
repeats:NO];
var scrollView = [_draggingDestination isKindOfClass:[CPView class]] ? [_draggingDestination enclosingScrollView] : nil;
if (scrollView)
{
var contentView = [scrollView contentView],
bounds = [contentView bounds],
insetBounds = CGRectInset(bounds, 10, 10),
eventLocation = [contentView convertPoint:_draggingLocation fromView:nil],
deltaX = 0,
deltaY = 0;
if (!CGRectContainsPoint(insetBounds, eventLocation))
{
if ([scrollView hasVerticalScroller])
{
if (eventLocation.y < CGRectGetMinY(insetBounds))
deltaY = CGRectGetMinY(insetBounds) - eventLocation.y;
else if (eventLocation.y > CGRectGetMaxY(insetBounds))
deltaY = CGRectGetMaxY(insetBounds) - eventLocation.y;
if (deltaY < -insetBounds.size.height)
deltaY = -insetBounds.size.height;
if (deltaY > insetBounds.size.height)
deltaY = insetBounds.size.height;
}
if ([scrollView hasHorizontalScroller])
{
if (eventLocation.x < CGRectGetMinX(insetBounds))
deltaX = CGRectGetMinX(insetBounds) - eventLocation.x;
else if (eventLocation.x > CGRectGetMaxX(insetBounds))
deltaX = CGRectGetMaxX(insetBounds) - eventLocation.x;
if (deltaX < -insetBounds.size.width)
deltaX = -insetBounds.size.width;
if (deltaX > insetBounds.size.width)
deltaX = insetBounds.size.width;
}
[contentView scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
}
}
}
return dragOperation;
}
- (void)_sendPeriodicDraggingUpdate:(CPTimer)aTimer
{
var userInfo = [aTimer userInfo];
_dragOperation = [self draggingUpdatedInPlatformWindow:[userInfo objectForKey:@"platformWindow"]
location:[userInfo objectForKey:@"location"]];
}
- (void)draggingEndedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation operation:(CPDragOperation)anOperation
{
[_draggingUpdateTimer invalidate];
_draggingUpdateTimer = nil;
[_draggedView removeFromSuperview];
if (![CPPlatform supportsDragAndDrop])
[_draggedWindow orderOut:self];
if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_endAt_operation_)
if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_endedAt_operation_)
[_draggingSource draggedImage:[_draggedView image] endedAt:aLocation operation:anOperation];
else if (_implementedDraggingSourceMethods & CPDraggingSource_draggedView_endedAt_operation_)
[_draggingSource draggedView:_draggedView endedAt:aLocation operation:anOperation];
@@ -277,8 +327,8 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
- (void)performDragOperationInPlatformWindow:(CPPlatformWindow)aPlatformWindow
{
if (_draggingDestination &&
(![_draggingDestination respondsToSelector:@selector(prepareForDragOperation:)] || [_draggingDestination prepareForDragOperation:CPDragServerDraggingInfo]) &&
if (_draggingDestination &&
(![_draggingDestination respondsToSelector:@selector(prepareForDragOperation:)] || [_draggingDestination prepareForDragOperation:CPDragServerDraggingInfo]) &&
(![_draggingDestination respondsToSelector:@selector(performDragOperation:)] || [_draggingDestination performDragOperation:CPDragServerDraggingInfo]) &&
[_draggingDestination respondsToSelector:@selector(concludeDragOperation:)])
[_draggingDestination concludeDragOperation:CPDragServerDraggingInfo];
@@ -342,8 +392,8 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
if ([_draggingSource respondsToSelector:@selector(draggedImage:movedTo:)])
_implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_movedTo_;
if ([_draggingSource respondsToSelector:@selector(draggedImage:endAt:operation:)])
_implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_endAt_operation_;
if ([_draggingSource respondsToSelector:@selector(draggedImage:endedAt:operation:)])
_implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_endedAt_operation_;
}
else
{
@@ -404,13 +454,25 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
// Stop tracking events.
return;
}
[self draggingSourceUpdatedWithGlobalLocation:platformWindowLocation];
_dragOperation = [self draggingUpdatedInPlatformWindow:platformWindow location:platformWindowLocation];
else if (type === CPKeyDown)
{
var keyCode = [anEvent keyCode];
if (keyCode === CPEscapeKeyCode)
{
_dragOperation = CPDragOperationNone;
[self draggingEndedInPlatformWindow:platformWindow globalLocation:CGPointMakeZero() operation:_dragOperation];
return;
}
}
else
{
[self draggingSourceUpdatedWithGlobalLocation:platformWindowLocation];
_dragOperation = [self draggingUpdatedInPlatformWindow:platformWindow location:platformWindowLocation];
}
// If we're not a mouse up, then we're going to want to grab the next event.
[CPApp setTarget:self selector:@selector(trackDragging:)
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPKeyDownMask
untilDate:nil inMode:0 dequeue:NO];
}
+170 -40
View File
@@ -21,8 +21,7 @@
*/
@import <Foundation/CPObject.j>
#include "CoreGraphics/CGGeometry.h"
@import "CPText.j"
CPLeftMouseDown = 1;
@@ -41,7 +40,7 @@ CPAppKitDefined = 13;
CPSystemDefined = 14;
CPApplicationDefined = 15;
CPPeriodic = 16;
CPCursorUpdate = 17;
CPCursorUpdate = 17;
CPScrollWheel = 22;
CPOtherMouseDown = 25;
CPOtherMouseUp = 26;
@@ -52,8 +51,7 @@ CPTouchStart = 28;
CPTouchMove = 29;
CPTouchEnd = 30;
CPTouchCancel = 31;
CPAlphaShiftKeyMask = 1 << 16;
CPShiftKeyMask = 1 << 17;
CPControlKeyMask = 1 << 18;
@@ -87,26 +85,102 @@ CPPeriodicMask = 1 << CPPeriodic;
CPScrollWheelMask = 1 << CPScrollWheel;
CPAnyEventMask = 0xffffffff;
CPDOMEventDoubleClick = "dblclick",
CPDOMEventMouseDown = "mousedown",
CPDOMEventMouseUp = "mouseup",
CPDOMEventMouseMoved = "mousemove",
CPDOMEventMouseDragged = "mousedrag",
CPDOMEventKeyUp = "keyup",
CPDOMEventKeyDown = "keydown",
CPDOMEventKeyPress = "keypress";
CPDOMEventCopy = "copy";
CPDOMEventPaste = "paste";
CPDOMEventScrollWheel = "mousewheel";
CPDOMEventTouchStart = "touchstart";
CPDOMEventTouchMove = "touchmove";
CPDOMEventTouchEnd = "touchend";
CPDOMEventTouchCancel = "touchcancel";
CPUpArrowFunctionKey = "\uF700";
CPDownArrowFunctionKey = "\uF701";
CPLeftArrowFunctionKey = "\uF702";
CPRightArrowFunctionKey = "\uF703";
CPF1FunctionKey = "\uF704";
CPF2FunctionKey = "\uF705";
CPF3FunctionKey = "\uF706";
CPF4FunctionKey = "\uF707";
CPF5FunctionKey = "\uF708";
CPF6FunctionKey = "\uF709";
CPF7FunctionKey = "\uF70A";
CPF8FunctionKey = "\uF70B";
CPF9FunctionKey = "\uF70C";
CPF10FunctionKey = "\uF70D";
CPF11FunctionKey = "\uF70E";
CPF12FunctionKey = "\uF70F";
CPF13FunctionKey = "\uF710";
CPF14FunctionKey = "\uF711";
CPF15FunctionKey = "\uF712";
CPF16FunctionKey = "\uF713";
CPF17FunctionKey = "\uF714";
CPF18FunctionKey = "\uF715";
CPF19FunctionKey = "\uF716";
CPF20FunctionKey = "\uF717";
CPF21FunctionKey = "\uF718";
CPF22FunctionKey = "\uF719";
CPF23FunctionKey = "\uF71A";
CPF24FunctionKey = "\uF71B";
CPF25FunctionKey = "\uF71C";
CPF26FunctionKey = "\uF71D";
CPF27FunctionKey = "\uF71E";
CPF28FunctionKey = "\uF71F";
CPF29FunctionKey = "\uF720";
CPF30FunctionKey = "\uF721";
CPF31FunctionKey = "\uF722";
CPF32FunctionKey = "\uF723";
CPF33FunctionKey = "\uF724";
CPF34FunctionKey = "\uF725";
CPF35FunctionKey = "\uF726";
CPInsertFunctionKey = "\uF727";
CPDeleteFunctionKey = "\uF728";
CPHomeFunctionKey = "\uF729";
CPBeginFunctionKey = "\uF72A";
CPEndFunctionKey = "\uF72B";
CPPageUpFunctionKey = "\uF72C";
CPPageDownFunctionKey = "\uF72D";
CPPrintScreenFunctionKey = "\uF72E";
CPScrollLockFunctionKey = "\uF72F";
CPPauseFunctionKey = "\uF730";
CPSysReqFunctionKey = "\uF731";
CPBreakFunctionKey = "\uF732";
CPResetFunctionKey = "\uF733";
CPStopFunctionKey = "\uF734";
CPMenuFunctionKey = "\uF735";
CPUserFunctionKey = "\uF736";
CPSystemFunctionKey = "\uF737";
CPPrintFunctionKey = "\uF738";
CPClearLineFunctionKey = "\uF739";
CPClearDisplayFunctionKey = "\uF73A";
CPInsertLineFunctionKey = "\uF73B";
CPDeleteLineFunctionKey = "\uF73C";
CPInsertCharFunctionKey = "\uF73D";
CPDeleteCharFunctionKey = "\uF73E";
CPPrevFunctionKey = "\uF73F";
CPNextFunctionKey = "\uF740";
CPSelectFunctionKey = "\uF741";
CPExecuteFunctionKey = "\uF742";
CPUndoFunctionKey = "\uF743";
CPRedoFunctionKey = "\uF744";
CPFindFunctionKey = "\uF745";
CPHelpFunctionKey = "\uF746";
CPModeSwitchFunctionKey = "\uF747";
CPEscapeFunctionKey = "\u001B";
CPDOMEventDoubleClick = "dblclick",
CPDOMEventMouseDown = "mousedown",
CPDOMEventMouseUp = "mouseup",
CPDOMEventMouseMoved = "mousemove",
CPDOMEventMouseDragged = "mousedrag",
CPDOMEventKeyUp = "keyup",
CPDOMEventKeyDown = "keydown",
CPDOMEventKeyPress = "keypress";
CPDOMEventCopy = "copy";
CPDOMEventPaste = "paste";
CPDOMEventScrollWheel = "mousewheel";
CPDOMEventTouchStart = "touchstart";
CPDOMEventTouchMove = "touchmove";
CPDOMEventTouchEnd = "touchend";
CPDOMEventTouchCancel = "touchcancel";
var _CPEventPeriodicEventPeriod = 0,
_CPEventPeriodicEventTimer = nil;
_CPEventPeriodicEventTimer = nil,
_CPEventUpperCaseRegex = new RegExp("[A-Z]");
/*!
/*!
@ingroup appkit
@class CPEvent
CPEvent encapsulates the details of a Cappuccino keyboard or mouse event.
@@ -128,7 +202,7 @@ var _CPEventPeriodicEventPeriod = 0,
BOOL _isARepeat;
unsigned _keyCode;
DOMEvent _DOMEvent;
float _deltaX;
float _deltaY;
float _deltaZ;
@@ -155,7 +229,7 @@ var _CPEventPeriodicEventPeriod = 0,
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)repeatKey keyCode:(unsigned short)code
{
return [[self alloc] _initKeyEventWithType:anEventType location:aPoint modifierFlags:modifierFlags
timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext
timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext
characters:characters charactersIgnoringModifiers:unmodCharacters isARepeat:repeatKey keyCode:code];
}
@@ -173,7 +247,7 @@ var _CPEventPeriodicEventPeriod = 0,
@throws CPInternalInconsistencyException if an invalid event type is provided
@return the new mouse event
*/
+ (id)mouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
+ (id)mouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
{
@@ -204,12 +278,12 @@ var _CPEventPeriodicEventPeriod = 0,
}
/* @ignore */
- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags
- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
{
self = [super init];
if (self)
{
_type = anEventType;
@@ -222,7 +296,7 @@ var _CPEventPeriodicEventPeriod = 0,
_pressure = aPressure;
_window = [CPApp windowWithWindowNumber:aWindowNumber];
}
return self;
}
@@ -232,7 +306,7 @@ var _CPEventPeriodicEventPeriod = 0,
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code
{
self = [super init];
if (self)
{
_type = anEventType;
@@ -246,7 +320,7 @@ var _CPEventPeriodicEventPeriod = 0,
_keyCode = code;
_windowNumber = aWindowNumber;
}
return self;
}
@@ -256,7 +330,7 @@ var _CPEventPeriodicEventPeriod = 0,
subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2
{
self = [super init];
if (self)
{
_type = anEventType;
@@ -267,7 +341,7 @@ var _CPEventPeriodicEventPeriod = 0,
_subtype = aSubtype;
_data1 = aData1;
_data2 = aData2;
}
}
return self;
}
@@ -345,7 +419,10 @@ var _CPEventPeriodicEventPeriod = 0,
*/
- (int)buttonNumber
{
return _buttonNumber;
if (_type === CPRightMouseDown || _type === CPRightMouseUp || _type === CPRightMouseDragged)
return 1;
return 0;
}
/*!
@@ -442,23 +519,76 @@ var _CPEventPeriodicEventPeriod = 0,
return _deltaZ;
}
- (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask
{
if (!aKeyEquivalent)
return NO;
if (_CPEventUpperCaseRegex.test(aKeyEquivalent))
aKeyEquivalentModifierMask |= CPShiftKeyMask;
if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (aKeyEquivalentModifierMask & CPCommandKeyMask))
{
aKeyEquivalentModifierMask |= CPControlKeyMask;
aKeyEquivalentModifierMask &= ~CPCommandKeyMask;
}
if ((_modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask)
return NO;
// Treat \r and \n as the same key equivalent. See issue #710.
if (_characters === CPNewlineCharacter || _characters === CPCarriageReturnCharacter)
return CPNewlineCharacter === aKeyEquivalent || CPCarriageReturnCharacter === aKeyEquivalent;
return [_characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame;
}
- (BOOL)_couldBeKeyEquivalent
{
if (_type !== CPKeyDown)
return NO;
var characterCount = _characters.length;
if (!characterCount)
return NO;
if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
return YES;
for(var i=0; i<characterCount; i++)
{
switch(_characters.charAt(i))
{
case CPBackspaceCharacter:
case CPDeleteCharacter:
case CPDeleteFunctionKey:
case CPTabCharacter:
case CPCarriageReturnCharacter:
case CPNewlineCharacter:
case CPEscapeFunctionKey:
case CPPageUpFunctionKey:
case CPPageDownFunctionKey:
case CPLeftArrowFunctionKey:
case CPUpArrowFunctionKey:
case CPRightArrowFunctionKey:
case CPDownArrowFunctionKey:
return YES;
}
}
// FIXME: More cases? Space?
return _type === CPKeyDown &&
_modifierFlags & (CPCommandKeyMask | CPControlKeyMask) &&
[_characters length] > 0;
return NO;
}
/*!
Generates periodic events every \c aPeriod seconds.
Gene rates periodic events every \c aPeriod seconds.
@param aDelay the number of seconds before the first event
@param aPeriod the length of time in seconds between successive events
*/
+ (void)startPeriodicEventsAfterDelay:(CPTimeInterval)aDelay withPeriod:(CPTimeInterval)aPeriod
{
_CPEventPeriodicEventPeriod = aPeriod;
// FIXME: OH TIMERS!!!
_CPEventPeriodicEventTimer = window.setTimeout(function() { _CPEventPeriodicEventTimer = window.setInterval(_CPEventFirePeriodEvent, aPeriod * 1000.0); }, aDelay * 1000.0);
}
@@ -470,9 +600,9 @@ var _CPEventPeriodicEventPeriod = 0,
{
if (_CPEventPeriodicEventTimer === nil)
return;
window.clearTimeout(_CPEventPeriodicEventTimer);
_CPEventPeriodicEventTimer = nil;
}
+1
View File
@@ -22,6 +22,7 @@
@import <Foundation/CPObject.j>
/*!
@ingroup appkit
@class CPFlashMovie
-1
View File
@@ -23,7 +23,6 @@
@import "CPFlashMovie.j"
@import "CPView.j"
#include "Platform/Platform.h"
var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
+73 -8
View File
@@ -20,6 +20,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPBundle.j>
@import "CPView.j"
var _CPFonts = {},
_CPFontSystemFontFace = @"Arial, sans-serif",
_CPWrapRegExp = new RegExp("\\s*,\\s*", "g");
@@ -28,7 +34,7 @@ var _CPFonts = {},
#define _CPCreateCSSString(aName, aSize, isBold) (isBold ? @"bold " : @"") + ROUND(aSize) + @"px " + ((aName === _CPFontSystemFontFace) ? aName : (@"\"" + aName.replace(_CPWrapRegExp, '", "') + @"\", " + _CPFontSystemFontFace))
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[_CPCreateCSSString(aName, aSize, isBold)]
/*!
/*!
@ingroup appkit
@class CPFont
@@ -38,11 +44,22 @@ var _CPFonts = {},
{
CPString _name;
float _size;
float _ascender;
float _descender;
float _lineHeight;
BOOL _isBold;
CPString _cssString;
}
+ (void)initialize
{
var systemFont = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:"CPSystemFontFace"];
if (systemFont)
_CPFontSystemFontFace = systemFont;
}
/*!
Returns a font with the specified name and size.
@param aName the name of the font
@@ -89,25 +106,64 @@ var _CPFonts = {},
@ignore
*/
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold
{
{
self = [super init];
if (self)
{
_name = aName;
_size = aSize;
_ascender = 0;
_descender = 0;
_lineHeight = 0;
_isBold = isBold;
_cssString = _CPCreateCSSString(_name, _size, _isBold);
_CPFonts[_cssString] = self;
}
return self;
}
/*!
Returns the font size (in points)
Returns the distance of the longest ascender's top y-coordinate from the baseline (in CSS px)
*/
- (float)ascender
{
if (!_ascender)
[self _getMetrics];
return _ascender;
}
/*!
Returns the bottom y coordinate (in CSS px), offset from the baseline, of the receiver's longest descender.
Thus, if the longest descender extends 2 points below the baseline, descender will return 2.
*/
- (float)descender
{
if (!_descender)
[self _getMetrics];
return _descender;
}
/*!
Returns the default line height.
NOTE: This was moved from NSFont to NSLayoutManager in Cocoa, but since there is no CPLayoutManager, it has been kept here.
*/
- (float)defaultLineHeightForFont
{
if (!_lineHeight)
[self _getMetrics];
return _lineHeight;
}
/*!
Returns the font size (in CSS px)
*/
- (float)size
{
@@ -140,6 +196,15 @@ var _CPFonts = {},
return [CPString stringWithFormat:@"%@ %@ %f pt.", [super description], [self familyName], [self size]];
}
- (void)_getMetrics
{
var metrics = [CPString metricsOfFont:self];
_ascender = [metrics objectForKey:@"ascender"];
_descender = [metrics objectForKey:@"descender"];
_lineHeight = [metrics objectForKey:@"lineHeight"];
}
@end
var CPFontNameKey = @"CPFontNameKey",
+2 -2
View File
@@ -22,7 +22,7 @@
@import <Foundation/CPObject.j>
@import <AppKit/CPFont.j>
@import "CPFont.j"
var CPSharedFontManager = nil,
@@ -51,7 +51,7 @@ var CPSharedFontManager = nil,
// Changing the Default Font Conversion Classes
/*!
Sets the class that will be used to create the applcation's
Sets the class that will be used to create the application's
font manager.
*/
+ (void)setFontManagerFactory:(Class)aClass
+29 -15
View File
@@ -70,7 +70,7 @@ function CPPointMake(x, y)
*/
function CPRectInset(aRect, dX, dY)
{
return CPRectMake( aRect.origin.x + dX, aRect.origin.y + dY,
return CPRectMake( aRect.origin.x + dX, aRect.origin.y + dY,
aRect.size.width - 2 * dX, aRect.size.height - 2*dY);
}
@@ -96,13 +96,13 @@ function CPRectIntegral(aRect)
function CPRectIntersection(lhsRect, rhsRect)
{
var intersection = CPRectMake(
Math.max(CPRectGetMinX(lhsRect), CPRectGetMinX(rhsRect)),
Math.max(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)),
Math.max(CPRectGetMinX(lhsRect), CPRectGetMinX(rhsRect)),
Math.max(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)),
0, 0);
intersection.size.width = Math.min(CPRectGetMaxX(lhsRect), CPRectGetMaxX(rhsRect)) - CPRectGetMinX(intersection);
intersection.size.height = Math.min(CPRectGetMaxY(lhsRect), CPRectGetMaxY(rhsRect)) - CPRectGetMinY(intersection);
return CPRectIsEmpty(intersection) ? CPRectMakeZero() : intersection;
}
@@ -160,13 +160,13 @@ function CPRectStandardize(aRect)
standardized.origin.x += width;
standardized.size.width = -width;
}
if (height < 0.0)
{
standardized.origin.y += height;
standardized.size.height = -height;
}
return standardized;
}
@@ -183,7 +183,7 @@ function CPRectUnion(lhsRect, rhsRect)
minY = Math.min(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)),
maxX = Math.max(CPRectGetMaxX(lhsRect), CPRectGetMaxX(rhsRect)),
maxY = Math.max(CPRectGetMaxY(lhsRect), CPRectGetMaxY(rhsRect));
return CPRectMake(minX, minY, maxX - minX, maxY - minY);
}
@@ -222,8 +222,8 @@ function CPRectContainsPoint(aRect, aPoint)
{
return aPoint.x >= CPRectGetMinX(aRect) &&
aPoint.y >= CPRectGetMinY(aRect) &&
aPoint.x < CPRectGetMaxX(aRect) &&
aPoint.y < CPRectGetMaxY(aRect);
aPoint.x < CPRectGetMaxX(aRect) &&
aPoint.y < CPRectGetMaxY(aRect);
}
/*!
@@ -261,7 +261,7 @@ function CPPointEqualToPoint(lhsPoint, rhsPoint)
*/
function CPRectEqualToRect(lhsRect, rhsRect)
{
return CPPointEqualToPoint(lhsRect.origin, rhsRect.origin) &&
return CPPointEqualToPoint(lhsRect.origin, rhsRect.origin) &&
CPSizeEqualToSize(lhsRect.size, rhsRect.size);
}
@@ -380,6 +380,20 @@ function CPRectIsNull(aRect)
return aRect.size.width <= 0.0 || aRect.size.height <= 0.0;
}
/*!
Creates two rectangles -- slice and rem -- from inRect, by dividing inRect
with a line that's parallel to the side of inRect specified by edge.
The size of slice is determined by amount, which specifies the distance from edge.
slice and rem must not be NULL.
@group CGRect
*/
function CPDivideRect(inRect, slice, rem, amount, edge)
{
CGRectDivide(inRect, slice, rem, amount, edge);
}
/*!
Returns \c YES if the two CGSizes are identical.
@group CGSize
@@ -434,7 +448,7 @@ function CPStringFromRect(aRect)
function CPPointFromString(aString)
{
var comma = aString.indexOf(',');
return { x:parseFloat(aString.substr(1, comma - 1), 10), y:parseFloat(aString.substring(comma + 1, aString.length), 10) };
}
@@ -447,7 +461,7 @@ function CPPointFromString(aString)
function CPSizeFromString(aString)
{
var comma = aString.indexOf(',');
return { width:parseFloat(aString.substr(1, comma - 1), 10), height:parseFloat(aString.substring(comma + 1, aString.length), 10) };
}
@@ -460,7 +474,7 @@ function CPSizeFromString(aString)
function CPRectFromString(aString)
{
var comma = aString.indexOf(',', aString.indexOf(',') + 1);
return { origin:CPPointFromString(aString.substr(1, comma - 1)), size:CPSizeFromString(aString.substring(comma + 2, aString.length)) };
}
@@ -504,6 +518,6 @@ function CPPointMakeZero()
return CPPointMake(0, 0, 0);
}
/*!
/*!
@}
*/
+108
View File
@@ -0,0 +1,108 @@
/*
* CPGraphics.j
* AppKit
*
* Created by Francisco Tolmasky.
* Copyright 2010, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPColor.j"
@import "CPGraphicsContext.j"
function CPDrawTiledRects(
/* CGRect */ boundsRect,
/* CGRect */ clipRect,
/* CPRectEdge[] */ sides,
/* float[] */ grays)
{
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]);
return CPDrawColorTiledRects(boundsRect, clipRect, sides, colors);
}
function CPDrawColorTiledRects(
/* CGRect */ boundsRect,
/* CGRect */ clipRect,
/* CPRectEdge[] */ sides,
/* CPColor[] */ colors)
{
if (sides.length != colors.length)
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and colors (length: " + colors.length + ") must have the same length."];
var resultRect = _CGRectMakeCopy(boundsRect),
slice = _CGRectMakeZero(),
remainder = _CGRectMakeZero(),
context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSaveGState(context);
CGContextSetLineWidth(context, 1.0);
for (var sideIndex = 0; sideIndex < sides.length; ++sideIndex)
{
var side = sides[sideIndex];
CGRectDivide(resultRect, slice, remainder, 1.0, side);
resultRect = remainder;
slice = CGRectIntersection(slice, clipRect);
// Cocoa docs say that only slices that are within the clipRect are actually drawn
if (_CGRectIsEmpty(slice))
continue;
var minX, maxX, minY, maxY;
if (side == CPMinXEdge || side == CPMaxXEdge)
{
// Make sure we have at least 1 pixel to draw a line
if (_CGRectGetWidth(slice) < 1.0)
continue;
minX = _CGRectGetMinX(slice) + 0.5;
maxX = minX;
minY = _CGRectGetMinY(slice);
maxY = _CGRectGetMaxY(slice);
}
else // CPMinYEdge || CPMaxYEdge
{
// Make sure we have at least 1 pixel to draw a line
if (_CGRectGetHeight(slice) < 1.0)
continue;
minX = _CGRectGetMinX(slice);
maxX = _CGRectGetMaxX(slice);
minY = _CGRectGetMinY(slice) + 0.5;
maxY = minY;
}
CGContextBeginPath(context);
CGContextMoveToPoint(context, minX, minY);
CGContextAddLineToPoint(context, maxX, maxY);
CGContextSetStrokeColor(context, colors[sideIndex]);
CGContextStrokePath(context);
}
CGContextRestoreGState(context);
return resultRect;
}
+5
View File
@@ -20,6 +20,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import "CGContext.j"
var CPGraphicsContextCurrent = nil;
/*!
+9 -6
View File
@@ -28,8 +28,6 @@
@import "CPGeometry.j"
#include "Platform/Platform.h"
CPImageLoadStatusInitialized = 0;
CPImageLoadStatusLoading = 1;
@@ -193,6 +191,9 @@ function CPAppKitImage(aFilename, aSize)
var imageOrSize = AppKitImageForNames[aName];
if (!imageOrSize)
return nil;
if (!imageOrSize.isa)
{
imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize);
@@ -205,17 +206,19 @@ function CPAppKitImage(aFilename, aSize)
return imageOrSize;
}
- (void)setName:(CPString)aName
- (BOOL)setName:(CPString)aName
{
if (_name === aName)
return;
return YES;
if (imagesForNames[aName] === self)
imagesForNames[aName] = nil;
if (imagesForNames[aName])
return NO;
_name = aName;
imagesForNames[aName] = self;
return YES;
}
- (CPString)name
+102 -18
View File
@@ -26,16 +26,23 @@
@import "CPImage.j"
@import "CPShadowView.j"
#include "Platform/Platform.h"
#include "Platform/DOM/CPDOMDisplayServer.h"
#include "CoreGraphics/CGGeometry.h"
CPScaleProportionally = 0;
CPScaleToFit = 1;
CPScaleNone = 2;
var CPImageViewShadowBackgroundColor = nil;
CPImageAlignCenter = 0;
CPImageAlignTop = 1;
CPImageAlignTopLeft = 2;
CPImageAlignTopRight = 3;
CPImageAlignLeft = 4;
CPImageAlignBottom = 5;
CPImageAlignBottomLeft = 6;
CPImageAlignBottomRight = 7;
CPImageAlignRight = 8;
var CPImageViewShadowBackgroundColor = nil,
CPImageViewEmptyPlaceholderImage = nil;
var LEFT_SHADOW_INSET = 3.0,
RIGHT_SHADOW_INSET = 3.0,
@@ -52,14 +59,22 @@ var LEFT_SHADOW_INSET = 3.0,
*/
@implementation CPImageView : CPControl
{
DOMElement _DOMImageElement;
DOMElement _DOMImageElement;
BOOL _hasShadow;
CPView _shadowView;
BOOL _hasShadow;
CPView _shadowView;
BOOL _isEditable;
BOOL _isEditable;
CGRect _imageRect;
CGRect _imageRect;
CPImageAlignment _imageAlignment;
}
+ (void)initialize
{
var bundle = [CPBundle bundleForClass:[CPView class]];
CPImageViewEmptyPlaceholderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"empty.png"]];
}
- (id)initWithFrame:(CGRect)aFrame
@@ -120,7 +135,7 @@ var LEFT_SHADOW_INSET = 3.0,
var newImage = [self objectValue];
#if PLATFORM(DOM)
_DOMImageElement.src = newImage ? [newImage filename] : "";
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
#endif
var size = [newImage size];
@@ -191,6 +206,30 @@ var LEFT_SHADOW_INSET = 3.0,
[self hideOrDisplayContents];
}
/*!
Sets the type of image alignment that should be used to
render the image.
@param anImageAlignment the type of scaling to use
*/
- (void)setImageAlignment:(CPImageAlignment)anImageAlignment
{
if (_imageAlignment == anImageAlignment)
return;
_imageAlignment = anImageAlignment;
if (![self image])
return;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
- (unsigned)imageAlignment
{
return _imageAlignment;
}
/*!
Sets the type of image scaling that should be used to
render the image.
@@ -318,8 +357,45 @@ var LEFT_SHADOW_INSET = 3.0,
#endif
}
var x = (boundsWidth - width) / 2.0,
y = (boundsHeight - height) / 2.0;
var x, y;
switch (_imageAlignment)
{
case CPImageAlignLeft:
case CPImageAlignTopLeft:
case CPImageAlignBottomLeft:
x = 0.0;
break;
case CPImageAlignRight:
case CPImageAlignTopRight:
case CPImageAlignBottomRight:
x = boundsWidth - width;
break;
default:
x = (boundsWidth - width) / 2.0;
break;
}
switch (_imageAlignment)
{
case CPImageAlignTop:
case CPImageAlignTopLeft:
case CPImageAlignTopRight:
y = 0.0;
break;
case CPImageAlignBottom:
case CPImageAlignBottomLeft:
case CPImageAlignBottomRight:
y = boundsHeight - height;
break;
default:
y = (boundsHeight - height) / 2.0;
break;
}
#if PLATFORM(DOM)
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y);
@@ -365,20 +441,26 @@ var LEFT_SHADOW_INSET = 3.0,
return _isEditable;
}
- (void)performDragOperation:(CPDraggingInfo)aSender
- (BOOL)performDragOperation:(CPDraggingInfo)aSender
{
var images = [CPKeyedUnarchiver unarchiveObjectWithData:[[aSender draggingPasteboard] dataForType:CPImagesPboardType]];
if ([images count])
{
[self setImage:images[0]];
[self sendAction:[self action] to:[self target]];
}
return YES;
}
@end
var CPImageViewImageKey = @"CPImageViewImageKey",
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
var CPImageViewImageKey = @"CPImageViewImageKey",
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
CPImageViewImageAlignmentKey = @"CPImageViewImageAlignmentKey",
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
@implementation CPImageView (CPCoding)
@@ -411,6 +493,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
#endif
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
[self setImageAlignment:[aCoder decodeIntForKey:CPImageViewImageAlignmentKey]];
if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO)
[self setEditable:YES];
@@ -445,6 +528,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
_subviews = actualSubviews;
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
[aCoder encodeInt:_imageAlignment forKey:CPImageViewImageAlignmentKey];
if (_isEditable)
[aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey];
+263
View File
@@ -0,0 +1,263 @@
/*
* CPKeyBinding.j
* AppKit
*
* Created by Nicholas Small.
* Copyright 2010, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import "CPEvent.j"
CPStandardKeyBindings = {
@"@.": @"cancelOperation:",
@"^a": @"moveToBeginningOfParagraph:",
@"^$a": @"moveToBeginningOfParagraphAndModifySelection:",
@"^b": @"moveBackward:",
@"^$b": @"moveBackwardAndModifySelection:",
@"^~b": @"moveWordBackward:",
@"^~$b": @"moveWordBackwardAndModifySelection:",
@"^d": @"deleteForward:",
@"^e": @"moveToEndOfParagraph:",
@"^$e": @"moveToEndOfParagraphAndModifySelection:",
@"^f": @"moveForward:",
@"^$f": @"moveForwardAndModifySelection:",
@"^~f": @"moveWordForward:",
@"^~$f": @"moveWordForwardAndModifySelection:",
@"^h": @"deleteBackward:",
@"^k": @"deleteToEndOfParagraph:",
@"^l": @"centerSelectionInVisibleArea:",
@"^n": @"moveDown:",
@"^$n": @"moveDownAndModifySelection:",
@"^o": [@"insertNewlineIgnoringFieldEditor:", @"moveBackward:"],
@"^p": @"moveUp:",
@"^$p": @"moveUpAndModifySelection:",
@"^t": @"transpose:",
@"^v": @"pageDown:",
@"^$v": @"pageDownAndModifySelection:",
@"^y": @"yank:"
};
CPStandardKeyBindings[CPNewlineCharacter] = @"insertNewline:";
CPStandardKeyBindings[CPCarriageReturnCharacter] = @"insertNewline:";
CPStandardKeyBindings[CPEnterCharacter] = @"insertNewline:";
CPStandardKeyBindings[@"~" + CPNewlineCharacter] = @"insertNewlineIgnoringFieldEditor:";
CPStandardKeyBindings[@"~" + CPCarriageReturnCharacter] = @"insertNewlineIgnoringFieldEditor:";
CPStandardKeyBindings[@"~" + CPEnterCharacter] = @"insertNewlineIgnoringFieldEditor:";
CPStandardKeyBindings[@"^" + CPNewlineCharacter] = @"insertLineBreak:";
CPStandardKeyBindings[@"^" + CPCarriageReturnCharacter] = @"insertLineBreak:";
CPStandardKeyBindings[@"^" + CPEnterCharacter] = @"insertLineBreak:";
CPStandardKeyBindings[CPBackspaceCharacter] = @"deleteBackward:";
CPStandardKeyBindings[@"~" + CPBackspaceCharacter] = @"deleteWordBackward:";
CPStandardKeyBindings[CPDeleteCharacter] = @"deleteBackward:";
CPStandardKeyBindings[@"@" + CPDeleteCharacter] = @"deleteToBeginningOfLine:";
CPStandardKeyBindings[@"~" + CPDeleteCharacter] = @"deleteWordBackward:";
CPStandardKeyBindings[@"^" + CPDeleteCharacter] = @"deleteBackwardByDecomposingPreviousCharacter:";
CPStandardKeyBindings[@"^~" + CPDeleteCharacter] = @"deleteWordBackward:";
CPStandardKeyBindings[CPDeleteFunctionKey] = @"deleteForward:";
CPStandardKeyBindings[@"~" + CPDeleteFunctionKey] = @"deleteWordForward:";
CPStandardKeyBindings[CPTabCharacter] = @"insertTab:";
CPStandardKeyBindings[@"~" + CPTabCharacter] = @"insertTabIgnoringFieldEditor:";
CPStandardKeyBindings[@"^" + CPTabCharacter] = @"selectNextKeyView:";
CPStandardKeyBindings[CPBackTabCharacter] = @"insertBacktab:";
CPStandardKeyBindings[@"^" + CPBackTabCharacter] = @"selectPreviousKeyView:";
CPStandardKeyBindings[CPEscapeFunctionKey] = @"cancelOperation:";
CPStandardKeyBindings[@"~" + CPEscapeFunctionKey] = @"complete:";
CPStandardKeyBindings[CPF5FunctionKey] = @"complete:";
CPStandardKeyBindings[CPLeftArrowFunctionKey] = @"moveLeft:";
CPStandardKeyBindings[@"~" + CPLeftArrowFunctionKey] = @"moveWordLeft:";
CPStandardKeyBindings[@"^" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLine:";
CPStandardKeyBindings[@"@" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLine:";
CPStandardKeyBindings[@"$" + CPLeftArrowFunctionKey] = @"moveLeftAndModifySelection:";
CPStandardKeyBindings[@"$~" + CPLeftArrowFunctionKey] = @"moveWordLeftAndModifySelection:";
CPStandardKeyBindings[@"$^" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLineAndModifySelection:";
CPStandardKeyBindings[@"$@" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLineAndModifySelection:";
CPStandardKeyBindings[@"@^" + CPLeftArrowFunctionKey] = @"makeBaseWritingDirectionRightToLeft:";
CPStandardKeyBindings[@"@^~" + CPLeftArrowFunctionKey] = @"makeTextWritingDirectionRightToLeft:";
CPStandardKeyBindings[CPRightArrowFunctionKey] = @"moveRight:";
CPStandardKeyBindings[@"~" + CPRightArrowFunctionKey] = @"moveWordRight:";
CPStandardKeyBindings[@"^" + CPRightArrowFunctionKey] = @"moveToRightEndOfLine:";
CPStandardKeyBindings[@"@" + CPRightArrowFunctionKey] = @"moveToRightEndOfLine:";
CPStandardKeyBindings[@"$" + CPRightArrowFunctionKey] = @"moveRightAndModifySelection:";
CPStandardKeyBindings[@"$~" + CPRightArrowFunctionKey] = @"moveWordRightAndModifySelection:";
CPStandardKeyBindings[@"$^" + CPRightArrowFunctionKey] = @"moveToRightEndOfLineAndModifySelection:";
CPStandardKeyBindings[@"$@" + CPRightArrowFunctionKey] = @"moveToRightEndOfLineAndModifySelection:";
CPStandardKeyBindings[@"@^" + CPRightArrowFunctionKey] = @"makeBaseWritingDirectionLeftToRight:";
CPStandardKeyBindings[@"@^~" + CPRightArrowFunctionKey] = @"makeTextWritingDirectionLeftToRight:";
CPStandardKeyBindings[CPUpArrowFunctionKey] = @"moveUp:";
CPStandardKeyBindings[@"~" + CPUpArrowFunctionKey] = [@"moveBackward:", @"moveToBeginningOfParagraph:"];
CPStandardKeyBindings[@"^" + CPUpArrowFunctionKey] = @"scrollPageUp:";
CPStandardKeyBindings[@"@" + CPUpArrowFunctionKey] = @"moveToBeginningOfDocument:";
CPStandardKeyBindings[@"$" + CPUpArrowFunctionKey] = @"moveUpAndModifySelection:";
CPStandardKeyBindings[@"$~" + CPUpArrowFunctionKey] = @"moveParagraphBackwardAndModifySelection:";
CPStandardKeyBindings[@"$@" + CPUpArrowFunctionKey] = @"moveToBeginningOfDocumentAndModifySelection:";
CPStandardKeyBindings[CPDownArrowFunctionKey] = @"moveDown:";
CPStandardKeyBindings[@"~" + CPDownArrowFunctionKey] = [@"moveForward:", @"moveToEndOfParagraph:"];
CPStandardKeyBindings[@"^" + CPDownArrowFunctionKey] = @"scrollPageDown:";
CPStandardKeyBindings[@"@" + CPDownArrowFunctionKey] = @"moveToEndOfDocument:";
CPStandardKeyBindings[@"$" + CPDownArrowFunctionKey] = @"moveDownAndModifySelection:";
CPStandardKeyBindings[@"$~" + CPDownArrowFunctionKey] = @"moveParagraphForwardAndModifySelection:";
CPStandardKeyBindings[@"$@" + CPDownArrowFunctionKey] = @"moveToEndOfDocumentAndModifySelection:";
CPStandardKeyBindings[@"@^" + CPDownArrowFunctionKey] = @"makeBaseWritingDirectionNatural:";
CPStandardKeyBindings[@"@^~" + CPDownArrowFunctionKey] = @"makeTextWritingDirectionNatural:";
CPStandardKeyBindings[CPHomeFunctionKey] = @"scrollToBeginningOfDocument:";
CPStandardKeyBindings[@"$" + CPHomeFunctionKey] = @"moveToBeginningOfDocumentAndModifySelection:";
CPStandardKeyBindings[CPEndFunctionKey] = @"scrollToEndOfDocument:";
CPStandardKeyBindings[@"$" + CPEndFunctionKey] = @"moveToEndOfDocumentAndModifySelection:";
CPStandardKeyBindings[CPPageUpFunctionKey] = @"scrollPageUp:";
CPStandardKeyBindings[@"~" + CPPageUpFunctionKey] = @"pageUp:";
CPStandardKeyBindings[@"$" + CPPageUpFunctionKey] = @"pageUpAndModifySelection:";
CPStandardKeyBindings[CPPageDownFunctionKey] = @"scrollPageDown:";
CPStandardKeyBindings[@"~" + CPPageDownFunctionKey] = @"pageDown:";
CPStandardKeyBindings[@"$" + CPPageDownFunctionKey] = @"pageDownAndModifySelection:";
var CPKeyBindingCache = {};
@implementation CPKeyBinding : CPObject
{
CPString _key;
unsigned _modifierFlags;
CPArray _selectors;
CPString _cacheName;
}
+ (void)initialize
{
if ([self class] !== CPKeyBinding)
return;
[self createKeyBindingsFromJSObject:CPStandardKeyBindings];
}
+ (void)createKeyBindingsFromJSObject:(JSObject)anObject
{
var binding;
for (binding in anObject)
[self cacheKeyBinding:[[CPKeyBinding alloc] initWithPhysicalKeyString:binding selectors:anObject[binding]]];
}
+ (void)cacheKeyBinding:(CPKeyBinding)aBinding
{
if (!aBinding)
return;
CPKeyBindingCache[[aBinding _cacheName]] = aBinding;
}
+ (CPKeyBinding)keyBindingForKey:(CPString)aKey modifierFlags:(unsigned)aFlag
{
var tempBinding = [[self alloc] initWithKey:aKey modifierFlags:aFlag selectors:nil];
return CPKeyBindingCache[[tempBinding _cacheName]];
}
+ (CPArray)selectorsForKey:(CPString)aKey modifierFlags:(unsigned)aFlag
{
return [[self keyBindingForKey:aKey modifierFlags:aFlag] selectors];
}
- (id)initWithPhysicalKeyString:(CPString)binding selectors:(CPArray)selectors
{
var components = binding.split(@""),
modifierFlags = ([components containsObject:@"$"] ? CPShiftKeyMask : 0) |
([components containsObject:@"^"] ? CPControlKeyMask : 0) |
([components containsObject:@"~"] ? CPAlternateKeyMask : 0) |
([components containsObject:@"@"] ? CPCommandKeyMask : 0);
if (![selectors isKindOfClass:CPArray])
selectors = [selectors];
return [self initWithKey:[components lastObject] modifierFlags:modifierFlags selectors:selectors];
}
- (id)initWithKey:(CPString)aKey modifierFlags:(unsigned)aFlag selectors:(CPArray)selectors
{
self = [super init];
if (self)
{
_key = aKey;
_modifierFlags = aFlag;
_selectors = selectors;
// We normalize our key binding string in order to properly cache it.
// We want to ensure the modifiers are always in the same order.
var cacheName = [];
if (_modifierFlags & CPCommandKeyMask)
cacheName.push(@"@");
if (_modifierFlags & CPControlKeyMask)
cacheName.push(@"^");
if (_modifierFlags & CPAlternateKeyMask)
cacheName.push(@"~");
if (_modifierFlags & CPShiftKeyMask)
cacheName.push(@"$");
cacheName.push(_key);
_cacheName = cacheName.join(@"");
}
return self;
}
- (CPString)key
{
return _key;
}
- (unsigned)modifierFlags
{
return _modifierFlags;
}
- (CPArray)selectors
{
return _selectors;
}
- (CPString)_cacheName
{
return _cacheName;
}
- (BOOL)isEqual:(CPKeyBinding)rhs
{
return _key === [rhs key] && _modifierFlags === [rhs modifierFlags];
}
- (CPString)description
{
return [CPString stringWithFormat:@"<KeyBinding string: '%@' modifierFlags: 0x%lx selectors: %@>", _key, _modifierFlags, _selectors];
}
@end
+472
View File
@@ -0,0 +1,472 @@
/*
* CPKeyValueBinding.j
* AppKit
*
* Created by Ross Boucher 1/13/09
* Copyright 280 North, Inc.
*
* Adapted from GNUStep
* Released under the LGPL.
*
* 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 <Foundation/CPDictionary.j>
@import <Foundation/CPValueTransformer.j>
var exposedBindingsMap = [CPDictionary new],
bindingsMap = [CPDictionary new];
var CPBindingOperationAnd = 0,
CPBindingOperationOr = 1;
@implementation CPKeyValueBinding : CPObject
{
CPDictionary _info;
id _source;
}
+ (void)exposeBinding:(CPString)aBinding forClass:(Class)aClass
{
var bindings = [exposedBindingsMap objectForKey:[aClass hash]];
if (!bindings)
{
bindings = [];
[exposedBindingsMap setObject:bindings forKey:[aClass hash]];
}
bindings.push(aBinding);
}
+ (CPArray)exposedBindingsForClass:(Class)aClass
{
return [[exposedBindingsMap objectForKey:[aClass hash]] copy];
}
+ (CPKeyValueBinding)getBinding:(CPString)aBinding forObject:(id)anObject
{
return [[bindingsMap objectForKey:[anObject hash]] objectForKey:aBinding];
}
+ (CPDictionary)infoForBinding:(CPString)aBinding forObject:(id)anObject
{
var theBinding = [self getBinding:aBinding forObject:anObject];
if (theBinding)
return theBinding._info;
return nil;
}
+ (CPDictionary)allBindingsForObject:(id)anObject
{
return [bindingsMap objectForKey:[anObject hash]];
}
+ (void)unbind:(CPString)aBinding forObject:(id)anObject
{
var bindings = [bindingsMap objectForKey:[anObject hash]];
if (!bindings)
return;
var theBinding = [bindings objectForKey:aBinding];
if (!theBinding)
return;
var infoDictionary = theBinding._info,
observedObject = [infoDictionary objectForKey:CPObservedObjectKey],
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey];
[observedObject removeObserver:theBinding forKeyPath:keyPath];
[bindings removeObjectForKey:aBinding];
}
+ (void)unbindAllForObject:(id)anObject
{
var bindings = [bindingsMap objectForKey:[anObject hash]];
if (!bindings)
return;
var allKeys = [bindings allKeys],
count = allKeys.length;
while (count--)
[anObject unbind:[bindings objectForKey:allKeys[count]]];
[bindingsMap removeObjectForKey:[anObject hash]];
}
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
{
self = [super init];
if (self)
{
_source = aSource;
_info = [CPDictionary dictionaryWithObjects:[aDestination, aKeyPath] forKeys:[CPObservedObjectKey, CPObservedKeyPathKey]];
if (options)
[_info setObject:options forKey:CPOptionsKey];
[aDestination addObserver:self forKeyPath:aKeyPath options:CPKeyValueObservingOptionNew context:aBinding];
var bindings = [bindingsMap objectForKey:[_source hash]];
if (!bindings)
{
bindings = [CPDictionary new];
[bindingsMap setObject:bindings forKey:[_source hash]];
}
[bindings setObject:self forKey:aName];
[self setValueFor:aBinding];
}
return self;
}
- (void)setValueFor:(CPString)aBinding
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey],
options = [_info objectForKey:CPOptionsKey],
newValue = [destination valueForKeyPath:keyPath],
isPlaceholder = CPIsControllerMarker(newValue);
if (isPlaceholder)
{
switch (newValue)
{
case CPMultipleValuesMarker:
newValue = [options objectForKey:CPMultipleValuesPlaceholderBindingOption] || @"Multiple Values";
break;
case CPNoSelectionMarker:
newValue = [options objectForKey:CPNoSelectionPlaceholderBindingOption] || @"No Selection";
break;
case CPNotApplicableMarker:
if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
[CPException raise:CPGenericException reason:@"can't transform non applicable key on: "+_source+" value: "+newValue];
newValue = [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable";
break;
}
}
else
{
// Only transform the value if the current value is not a placeholder
newValue = [self transformValue:newValue withOptions:options];
}
[_source setValue:newValue forKey:aBinding];
if ([_source respondsToSelector:@selector(_setCurrentValueIsPlaceholder:)])
[_source _setCurrentValueIsPlaceholder:isPlaceholder];
}
- (void)reverseSetValueFor:(CPString)aBinding
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey],
options = [_info objectForKey:CPOptionsKey],
newValue = [_source valueForKeyPath:aBinding];
newValue = [self reverseTransformValue:newValue withOptions:options];
[destination setValue:newValue forKeyPath:keyPath];
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context
{
if (!changes)
return;
[self setValueFor:context];
}
- (id)transformValue:(id)aValue withOptions:(CPDictionary)options
{
var valueTransformerName,
valueTransformer,
placeholder;
var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption],
valueTransformer;
if (valueTransformerName)
{
valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName];
if (!valueTransformer)
{
var valueTransformerClass = CPClassFromString(valueTransformerName);
if (valueTransformerClass)
{
valueTransformer = [[valueTransformerClass alloc] init];
[valueTransformerClass setValueTransformer:valueTransformer forName:valueTransformerName];
}
}
}
else
valueTransformer = [options objectForKey:CPValueTransformerBindingOption];
if (valueTransformer)
aValue = [valueTransformer transformedValue:aValue];
if (aValue === undefined || aValue === nil)
aValue = [options objectForKey:CPNullPlaceholderBindingOption] || nil;
return aValue;
}
- (id)reverseTransformValue:(id)aValue withOptions: (CPDictionary)options
{
var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption],
valueTransformer;
if (valueTransformerName)
valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName];
else
valueTransformer = [options objectForKey:CPValueTransformerBindingOption];
if (valueTransformer && [[valueTransformer class] allowsReverseTransformation])
aValue = [valueTransformer reverseTransformedValue:aValue];
return aValue;
}
@end
@implementation CPObject (KeyValueBindingCreation)
+ (void)exposeBinding:(CPString)aBinding
{
[CPKeyValueBinding exposeBinding:aBinding forClass:[self class]];
}
- (CPArray)exposedBindings
{
var exposedBindings = [],
theClass = [self class];
while (theClass)
{
var temp = [CPKeyValueBinding exposedBindingsForClass:theClass];
if (temp)
[exposedBindings addObjectsFromArray:temp];
theClass = [theClass superclass];
}
return exposedBindings;
}
- (Class)valueClassForBinding:(CPString)binding
{
return [CPString class];
}
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
{
if (!anObject || !aKeyPath)
return CPLog.error("Invalid object or path on "+self+" for "+aBinding);
//if (![[self exposedBindings] containsObject:aBinding])
// CPLog.warn("No binding exposed on "+self+" for "+aBinding);
[self unbind:aBinding];
[[CPKeyValueBinding alloc] initWithBinding:[self _replacementKeyPathForBinding:aBinding] name:aBinding to:anObject keyPath:aKeyPath options:options from:self];
}
- (CPDictionary)infoForBinding:(CPString)aBinding
{
return [CPKeyValueBinding infoForBinding:aBinding forObject:self];
}
- (void)unbind:(CPString)aBinding
{
[CPKeyValueBinding unbind:aBinding forObject:self];
}
- (id)_replacementKeyPathForBinding:(CPString)binding
{
return binding;
}
@end
@implementation _CPKeyValueOrBinding : CPKeyValueBinding
{
}
- (void)setValueFor:(CPString)aBinding
{
var bindings = [bindingsMap valueForKey:[_source hash]];
if (!bindings)
return;
[_source setValue:resolveMultipleValues(aBinding, bindings, CPBindingOperationOr) forKey:aBinding];
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context
{
[self setValueFor:context];
}
@end
@implementation _CPKeyValueAndBinding : CPKeyValueBinding
{
}
- (void)setValueFor:(CPString)aBinding
{
var bindings = [bindingsMap objectForKey:[_source hash]];
if (!bindings)
return;
[_source setValue:resolveMultipleValues(aBinding, bindings, CPBindingOperationAnd) forKey:aBinding];
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObejct change:(CPDictionary)changes context:(id)context
{
[self setValueFor:context];
}
@end
var resolveMultipleValues = function resolveMultipleValues(/*CPString*/key, /*CPDictionary*/bindings, /*GSBindingOperationKind*/operation)
{
var bindingName = key,
theBinding,
count = 1;
while (theBinding = [bindings objectForKey:bindingName])
{
var infoDictionary = theBinding._info,
object = [infoDictionary objectForKey:CPObservedObjectKey],
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey],
options = [infoDictionary objectForKey:CPOptionsKey];
var value = [theBinding transformValue:[object valueForKeyPath:keyPath] withOptions:options];
if (value == operation)
return operation;
bindingName = [CPString stringWithFormat:@"%@%i", key, ++count];
}
return !operation;
}
var invokeAction = function invokeAction(/*CPString*/targetKey, /*CPString*/argumentKey, /*CPDictionary*/bindings)
{
var theBinding = [bindings objectForKey:targetKey],
infoDictionary = theBinding._info,
object = [infoDictionary objectForKey:CPObservedObjectKey],
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey],
options = [infoDictionary objectForKey:CPOptionsKey],
target = [object valueForKeyPath:keyPath],
selector = [options objectForKey:CPSelectorNameBindingOption];
if (!target || !selector)
return;
var invocation = [CPInvocation invocationWithMethodSignature:[target methodSignatureForSelector:selector]];
[invocation setSelector:selector];
var bindingName = argumentKey,
count = 1;
while (theBinding = [bindings objectForKey:bindingName])
{
infoDictionary = theBinding._info;
keyPath = [infoDictionary objectForKey:CPObserverKeyPathKey];
object = [[infoDictionary objectForKey:CPObservedObjectKey] valueForKeyPath:keyPath];
if (object)
[invocation setArgument:object atIndex:++count];
bindingName = [CPString stringWithFormat:@"%@%i", argumentKey, count];
}
[invocation invoke];
}
// Keys in options dictionary
// Keys in dictionary returned by infoForBinding
CPObservedObjectKey = @"CPObservedObjectKey";
CPObservedKeyPathKey = @"CPObservedKeyPathKey";
CPOptionsKey = @"CPOptionsKey";
// special markers
CPMultipleValuesMarker = @"CPMultipleValuesMarker";
CPNoSelectionMarker = @"CPNoSelectionMarker";
CPNotApplicableMarker = @"CPNotApplicableMarker";
// Binding name constants
CPAlignmentBinding = @"CPAlignmentBinding";
CPEditableBinding = @"CPEditableBinding";
CPEnabledBinding = @"CPEnabledBinding";
CPFontBinding = @"CPFontBinding";
CPHiddenBinding = @"CPHiddenBinding";
CPSelectedIndexBinding = @"CPSelectedIndexBinding";
CPTextColorBinding = @"CPTextColorBinding";
CPToolTipBinding = @"CPToolTipBinding";
CPValueBinding = @"value";
//Binding options constants
CPAllowsEditingMultipleValuesSelectionBindingOption = @"CPAllowsEditingMultipleValuesSelectionBindingOption";
CPAllowsNullArgumentBindingOption = @"CPAllowsNullArgumentBindingOption";
CPConditionallySetsEditableBindingOption = @"CPConditionallySetsEditableBindingOption";
CPConditionallySetsEnabledBindingOption = @"CPConditionallySetsEnabledBindingOption";
CPConditionallySetsHiddenBindingOption = @"CPConditionallySetsHiddenBindingOption";
CPContinuouslyUpdatesValueBindingOption = @"CPContinuouslyUpdatesValueBindingOption";
CPCreatesSortDescriptorBindingOption = @"CPCreatesSortDescriptorBindingOption";
CPDeletesObjectsOnRemoveBindingsOption = @"CPDeletesObjectsOnRemoveBindingsOption";
CPDisplayNameBindingOption = @"CPDisplayNameBindingOption";
CPDisplayPatternBindingOption = @"CPDisplayPatternBindingOption";
CPHandlesContentAsCompoundValueBindingOption = @"CPHandlesContentAsCompoundValueBindingOption";
CPInsertsNullPlaceholderBindingOption = @"CPInsertsNullPlaceholderBindingOption";
CPInvokesSeparatelyWithArrayObjectsBindingOption = @"CPInvokesSeparatelyWithArrayObjectsBindingOption";
CPMultipleValuesPlaceholderBindingOption = @"CPMultipleValuesPlaceholderBindingOption";
CPNoSelectionPlaceholderBindingOption = @"CPNoSelectionPlaceholderBindingOption";
CPNotApplicablePlaceholderBindingOption = @"CPNotApplicablePlaceholderBindingOption";
CPNullPlaceholderBindingOption = @"CPNullPlaceholderBindingOption";
CPPredicateFormatBindingOption = @"CPPredicateFormatBindingOption";
CPRaisesForNotApplicableKeysBindingOption = @"CPRaisesForNotApplicableKeysBindingOption";
CPSelectorNameBindingOption = @"CPSelectorNameBindingOption";
CPSelectsAllWhenSettingContentBindingOption = @"CPSelectsAllWhenSettingContentBindingOption";
CPValidatesImmediatelyBindingOption = @"CPValidatesImmediatelyBindingOption";
CPValueTransformerNameBindingOption = @"CPValueTransformerNameBindingOption";
CPValueTransformerBindingOption = @"CPValueTransformerBindingOption";
CPIsControllerMarker = function(/*id*/anObject)
{
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker;
}
+58 -65
View File
@@ -31,9 +31,6 @@
@import "CPMenuItem.j"
@import "CPPanel.j"
#include "../CoreGraphics/CGGeometry.h"
#include "../Platform/Platform.h"
CPMenuDidAddItemNotification = @"CPMenuDidAddItemNotification";
CPMenuDidChangeItemNotification = @"CPMenuDidChangeItemNotification";
@@ -50,11 +47,11 @@ var _CPMenuBarVisible = NO,
_CPMenuBarAttributes = nil,
_CPMenuBarSharedWindow = nil;
/*!
/*!
@ingroup appkit
@class CPMenu
Menus provide the user with a list of actions and/or submenus. Submenus themselves are full fledged menus
Menus provide the user with a list of actions and/or submenus. Submenus themselves are full fledged menus
and so a heirarchical structure appears.
*/
@implementation CPMenu : CPObject
@@ -69,13 +66,13 @@ var _CPMenuBarVisible = NO,
float _minimumWidth;
CPMutableArray _items;
BOOL _autoenablesItems;
BOOL _showsStateColumn;
id _delegate;
CPMenuItem _highlightedIndex;
int _highlightedIndex;
_CPMenuWindow _menuWindow;
}
@@ -95,7 +92,7 @@ var _CPMenuBarVisible = NO,
{
if (_CPMenuBarVisible === menuBarShouldBeVisible)
return;
_CPMenuBarVisible = menuBarShouldBeVisible;
if ([CPPlatform supportsNativeMainMenu])
@@ -105,13 +102,13 @@ var _CPMenuBarVisible = NO,
{
if (!_CPMenuBarSharedWindow)
_CPMenuBarSharedWindow = [[_CPMenuBarWindow alloc] init];
[_CPMenuBarSharedWindow setMenu:[CPApp mainMenu]];
[_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle];
[_CPMenuBarSharedWindow setIconImage:_CPMenuBarIconImage];
[_CPMenuBarSharedWindow setIconImageAlphaValue:_CPMenuBarIconImageAlphaValue];
[_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
[_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]];
[_CPMenuBarSharedWindow setTitleColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleColor"]];
@@ -120,12 +117,12 @@ var _CPMenuBarVisible = NO,
[_CPMenuBarSharedWindow setHighlightColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightColor"]];
[_CPMenuBarSharedWindow setHighlightTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextColor"]];
[_CPMenuBarSharedWindow setHighlightTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]];
[_CPMenuBarSharedWindow orderFront:self];
}
else
[_CPMenuBarSharedWindow orderOut:self];
// FIXME: There must be a better way to do this.
#if PLATFORM(DOM)
[[CPPlatformWindow primaryPlatformWindow] resizeEvent:nil];
@@ -159,9 +156,9 @@ var _CPMenuBarVisible = NO,
{
if (_CPMenuBarAttributes == attributes)
return;
_CPMenuBarAttributes = [attributes copy];
var textColor = [attributes objectForKey:@"CPMenuBarTextColor"],
titleColor = [attributes objectForKey:@"CPMenuBarTitleColor"],
textShadowColor = [attributes objectForKey:@"CPMenuBarTextShadowColor"],
@@ -169,40 +166,40 @@ var _CPMenuBarVisible = NO,
highlightColor = [attributes objectForKey:@"CPMenuBarHighlightColor"],
highlightTextColor = [attributes objectForKey:@"CPMenuBarHighlightTextColor"],
highlightTextShadowColor = [attributes objectForKey:@"CPMenuBarHighlightTextShadowColor"];
if (!textColor && titleColor)
[_CPMenuBarAttributes setObject:titleColor forKey:@"CPMenuBarTextColor"];
else if (textColor && !titleColor)
[_CPMenuBarAttributes setObject:textColor forKey:@"CPMenuBarTitleColor"];
else if (!textColor && !titleColor)
{
[_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTextColor"];
[_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTitleColor"];
}
if (!textShadowColor && titleShadowColor)
[_CPMenuBarAttributes setObject:titleShadowColor forKey:@"CPMenuBarTextShadowColor"];
else if (textShadowColor && !titleShadowColor)
[_CPMenuBarAttributes setObject:textShadowColor forKey:@"CPMenuBarTitleShadowColor"];
else if (!textShadowColor && !titleShadowColor)
{
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTextShadowColor"];
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTitleShadowColor"];
}
if (!highlightColor)
[_CPMenuBarAttributes setObject:[CPColor colorWithCalibratedRed:94.0/255.0 green:130.0/255.0 blue:186.0/255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"];
if (!highlightTextColor)
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarHighlightTextColor"];
if (!highlightTextShadowColor)
[_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarHighlightTextShadowColor"];
if (_CPMenuBarSharedWindow)
{
[_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
@@ -231,7 +228,7 @@ var _CPMenuBarVisible = NO,
{
if (self === [CPApp mainMenu])
return MENUBAR_HEIGHT;
return 0.0;
}
@@ -249,18 +246,18 @@ var _CPMenuBarVisible = NO,
- (id)initWithTitle:(CPString)aTitle
{
self = [super init];
if (self)
{
_title = aTitle;
_items = [];
_autoenablesItems = YES;
_showsStateColumn = YES;
[self setMinimumWidth:0];
}
return self;
}
@@ -287,7 +284,7 @@ var _CPMenuBarVisible = NO,
[aMenuItem setMenu:self];
[_items insertObject:aMenuItem atIndex:anIndex];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidAddItemNotification
object:self
@@ -306,7 +303,7 @@ var _CPMenuBarVisible = NO,
- (CPMenuItem)insertItemWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent atIndex:(unsigned)anIndex
{
var item = [[CPMenuItem alloc] initWithTitle:aTitle action:anAction keyEquivalent:aKeyEquivalent];
[self insertItem:item atIndex:anIndex];
return item;
@@ -351,10 +348,10 @@ var _CPMenuBarVisible = NO,
{
if (anIndex < 0 || anIndex >= _items.length)
return;
[_items[anIndex] setMenu:nil];
[_items removeObjectAtIndex:anIndex];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidRemoveItemNotification
object:self
@@ -369,7 +366,7 @@ var _CPMenuBarVisible = NO,
{
if ([aMenuItem menu] != self)
return;
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidChangeItemNotification
object:self
@@ -385,10 +382,10 @@ var _CPMenuBarVisible = NO,
- (CPMenuItem)itemWithTag:(int)aTag
{
var index = [self indexOfItemWithTag:aTag];
if (index == CPNotFound)
return nil;
return _items[index];
}
@@ -400,10 +397,10 @@ var _CPMenuBarVisible = NO,
- (CPMenuItem)itemWithTitle:(CPString)aTitle
{
var index = [self indexOfItemWithTitle:aTitle];
if (index == CPNotFound)
return nil;
return _items[index];
}
@@ -442,7 +439,7 @@ var _CPMenuBarVisible = NO,
{
if ([aMenuItem menu] !== self)
return CPNotFound;
return [_items indexOfObjectIdenticalTo:aMenuItem];
}
@@ -455,7 +452,7 @@ var _CPMenuBarVisible = NO,
{
var index = 0,
count = _items.length;
for (; index < count; ++index)
if ([_items[index] title] === aTitle)
return index;
@@ -472,7 +469,7 @@ var _CPMenuBarVisible = NO,
{
var index = 0,
count = _items.length;
for (; index < count; ++index)
if ([_items[index] tag] == aTag)
return index;
@@ -490,11 +487,11 @@ var _CPMenuBarVisible = NO,
{
var index = 0,
count = _items.length;
for (; index < count; ++index)
{
var item = _items[index];
if ([item target] == aTarget && (!anAction || [item action] == anAction))
return index;
}
@@ -511,7 +508,7 @@ var _CPMenuBarVisible = NO,
{
var index = 0,
count = _items.length;
for (; index < count; ++index)
if ([[_items[index] representedObject] isEqual:anObject])
return index;
@@ -528,7 +525,7 @@ var _CPMenuBarVisible = NO,
{
var index = 0,
count = _items.length;
for (; index < count; ++index)
if ([_items[index] submenu] == aMenu)
return index;
@@ -546,7 +543,7 @@ var _CPMenuBarVisible = NO,
{
[aMenuItem setTarget:aMenuItem];
[aMenuItem setAction:@selector(submenuAction:)];
[aMenuItem setSubmenu:aMenu];
}
@@ -683,7 +680,7 @@ var _CPMenuBarVisible = NO,
itemIndex = [self indexOfItem:anItem];
if (itemIndex === CPNotFound)
throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, menu item " +
throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, menu item " +
anItem + " is not present in menu " + self;
}
@@ -747,6 +744,9 @@ var _CPMenuBarVisible = NO,
}
// Show it.
if ([CPPlatform isBrowser])
[menuWindow setPlatformWindow:[[aView window] platformWindow]];
[menuWindow orderFront:self];
// Track it.
@@ -781,10 +781,10 @@ var _CPMenuBarVisible = NO,
+ (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont
{
var delegate = [aMenu delegate];
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
[delegate menuWillOpen:aMenu];
if (!aFont)
aFont = [CPFont systemFontOfSize:12.0];
@@ -816,6 +816,9 @@ var _CPMenuBarVisible = NO,
[menuWindow setFrameOrigin:CGRectIntersection(unconstrainedFrame, constraintRect).origin];
}
if ([CPPlatform isBrowser])
[menuWindow setPlatformWindow:[[aView window] platformWindow]];
[menuWindow orderFront:self];
[[_CPMenuManager sharedMenuManager]
@@ -932,17 +935,7 @@ var _CPMenuBarVisible = NO,
var item = _items[index],
modifierMask = [item keyEquivalentModifierMask];
if ([item keyEquivalent] === [[item keyEquivalent] uppercaseString])
modifierMask |= CPShiftKeyMask;
if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (modifierMask & CPCommandKeyMask))
{
modifierMask |= CPControlKeyMask;
modifierMask &= ~CPCommandKeyMask;
}
if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) == modifierMask &&
[characters caseInsensitiveCompare:[item keyEquivalent]] == CPOrderedSame)
if ([anEvent _triggersKeyEquivalent:[item keyEquivalent] withModifierMask:[item keyEquivalentModifierMask]])
{
if ([item isEnabled])
[self performActionForItemAtIndex:index];
@@ -950,7 +943,7 @@ var _CPMenuBarVisible = NO,
{
//beep?
}
return YES;
}
@@ -969,7 +962,7 @@ var _CPMenuBarVisible = NO,
- (void)performActionForItemAtIndex:(unsigned)anIndex
{
var item = _items[anIndex];
[CPApp sendAction:[item action] to:[item target] from:item];
}
@@ -1058,7 +1051,7 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_title = [aCoder decodeObjectForKey:CPMenuTitleKey];
@@ -1070,7 +1063,7 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
[self setMinimumWidth:0];
}
return self;
}
+1 -4
View File
@@ -1,7 +1,4 @@
#include "../CoreGraphics/CGGeometry.h"
#include "../Platform/Platform.h"
@import "CPPanel.j"
@import "_CPMenuWindow.j"
+1 -4
View File
@@ -1,6 +1,3 @@
#include "../CoreGraphics/CGGeometry.h"
@import <Foundation/CPObject.j>
@@ -96,7 +93,7 @@ var SharedMenuManager = nil;
// Close Menu Event.
if (type === CPAppKitDefined)
return [self completeTracking]
return [self completeTracking];
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES];
+1 -2
View File
@@ -1,5 +1,4 @@
#include "../CoreGraphics/CGGeometry.h"
@import "CPWindow.j"
var _CPMenuWindowPool = [],
+91 -49
View File
@@ -29,7 +29,8 @@
@import "CPView.j"
@import "_CPMenuItemView.j"
/*!
/*!
@ingroup appkit
@class CPMenuItem
@@ -43,39 +44,39 @@
CPString _title;
//CPAttributedString _attributedTitle;
CPFont _font;
id _target;
SEL _action;
BOOL _isEnabled;
BOOL _isHidden;
int _tag;
int _state;
CPImage _image;
CPImage _alternateImage;
CPImage _onStateImage;
CPImage _offStateImage;
CPImage _mixedStateImage;
CPMenu _submenu;
CPMenu _menu;
CPString _keyEquivalent;
unsigned _keyEquivalentModifierMask;
int _mnemonicLocation;
BOOL _isAlternate;
int _indentationLevel;
CPString _toolTip;
id _representedObject;
CPView _view;
_CPMenuItemView _menuItemView;
}
@@ -94,19 +95,19 @@
- (id)initWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent
{
self = [super init];
if (self)
{
_isSeparator = NO;
_title = aTitle;
_action = anAction;
_isEnabled = YES;
_tag = 0;
_state = CPOffState;
_keyEquivalent = aKeyEquivalent || @"";
_keyEquivalentModifierMask = CPPlatformActionKeyMask;
@@ -114,7 +115,7 @@
_mnemonicLocation = CPNotFound;
}
return self;
}
@@ -152,7 +153,7 @@
{
if (_isHidden == isHidden)
return;
_isHidden = isHidden;
[_menu itemChanged:self];
@@ -173,9 +174,9 @@
{
if (_isHidden)
return YES;
var supermenu = [_menu supermenu];
if ([[supermenu itemAtIndex:[supermenu indexOfItemWithSubmenu:_menu]] isHiddenOrHasHiddenAncestor])
return YES;
@@ -228,11 +229,11 @@
if (_title == aTitle)
return;
_title = aTitle;
[_menuItemView setDirty];
[_menu itemChanged:self];
}
@@ -260,11 +261,11 @@
{
if (_font == aFont)
return;
_font = aFont;
[_menu itemChanged:self];
[_menuItemView setDirty];
}
@@ -316,9 +317,9 @@ CPOffState
{
if (_state == aState)
return;
_state = aState;
[_menu itemChanged:self];
[_menuItemView setDirty];
@@ -346,11 +347,11 @@ CPOffState
{
if (_image == anImage)
return;
_image = anImage;
[_menuItemView setDirty];
[_menu itemChanged:self];
}
@@ -388,7 +389,7 @@ CPOffState
{
if (_onStateImage == anImage)
return;
_onStateImage = anImage;
[_menu itemChanged:self];
}
@@ -409,7 +410,7 @@ CPOffState
{
if (_offStateImage == anImage)
return;
_offStateImage = anImage;
[_menu itemChanged:self];
}
@@ -430,7 +431,7 @@ CPOffState
{
if (_mixedStateImage == anImage)
return;
_mixedStateImage = anImage;
[_menu itemChanged:self];
}
@@ -591,7 +592,8 @@ CPControlKeyMask
return @"";
var string = _keyEquivalent.toUpperCase(),
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || string === _keyEquivalent;
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask ||
(string === _keyEquivalent && _keyEquivalent.toLowerCase() !== _keyEquivalent.toUpperCase());
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
{
@@ -648,14 +650,14 @@ CPControlKeyMask
- (void)setTitleWithMnemonicLocation:(CPString)aTitle
{
var location = [aTitle rangeOfString:@"&"].location;
if (location == CPNotFound)
[self setTitle:aTitle];
else
{
[self setTitle:[aTitle substringToIndex:location] + [aTitle substringFromIndex:location + 1]];
[self setMnemonicLocation:location];
}
}
}
/*!
@@ -696,7 +698,7 @@ CPControlKeyMask
{
if (aLevel < 0)
[CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than or equal to 0."];
_indentationLevel = MIN(15, aLevel);
}
@@ -755,11 +757,11 @@ CPControlKeyMask
{
if (_view === aView)
return;
_view = aView;
[_menuItemView setDirty];
[_menu itemChanged:self];
}
@@ -781,7 +783,48 @@ CPControlKeyMask
return [[self menu] highlightedItem] == self;
}
//
#pragma mark CPObject Overrides
/*!
Returns a copy of the item. The copy does not belong If the item has a submenu, it is NOT copied.
*/
- (id)copy
{
var item = [[CPMenuItem alloc] init];
// No point in going through accessors and doing lots of unnecessary state checking/updating
item._isSeparator = _isSeparator;
[item setTitle:_title];
[item setFont:_font];
[item setTarget:_target];
[item setAction:_action];
[item setEnabled:_isEnabled];
[item setHidden:_isHidden]
[item setTag:_tag];
[item setState:_state];
[item setImage:_image];
[item setAlternateImage:_alternateImage];
[item setOnStateImage:_onStateImage];
[item setOffStateImage:_offStateImage];
[item setMixedStateImage:_mixedStateImage];
[item setKeyEquivalent:_keyEquivalent];
[item setKeyEquivalentModifierMask:_keyEquivalentModifierMask];
[item setMnemonicLocation:_mnemonicLocation];
[item setAlternate:_isAlternate];
[item setIndentationLevel:_indentationLevel];
[item setToolTip:_toolTip];
[item setRepresentedObject:_representedObject];
return item;
}
- (id)mutableCopy
{
return [self copy];
}
#pragma mark Internal
/*
@ignore
@@ -790,7 +833,7 @@ CPControlKeyMask
{
if (!_menuItemView)
_menuItemView = [[_CPMenuItemView alloc] initWithFrame:CGRectMakeZero() forMenuItem:self];
return _menuItemView;
}
@@ -844,15 +887,15 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_isSeparator = [aCoder containsValueForKey:CPMenuItemIsSeparatorKey] && [aCoder decodeBoolForKey:CPMenuItemIsSeparatorKey];
_title = [aCoder decodeObjectForKey:CPMenuItemTitleKey];
// _font;
_target = [aCoder decodeObjectForKey:CPMenuItemTargetKey];
_action = [aCoder decodeObjectForKey:CPMenuItemActionKey];
@@ -860,7 +903,6 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
_isHidden = DEFAULT_VALUE(CPMenuItemIsHiddenKey, NO);
_tag = DEFAULT_VALUE(CPMenuItemTagKey, 0);
_state = DEFAULT_VALUE(CPMenuItemStateKey, CPOffState);
// int _state;
_image = DEFAULT_VALUE(CPMenuItemImageKey, nil);
_alternateImage = DEFAULT_VALUE(CPMenuItemAlternateImageKey, nil);
@@ -887,7 +929,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
_representedObject = DEFAULT_VALUE(CPMenuItemRepresentedObjectKey, nil);
_view = DEFAULT_VALUE(CPMenuItemViewKey, nil);
}
return self;
}
@@ -901,11 +943,11 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
[aCoder encodeBool:_isSeparator forKey:CPMenuItemIsSeparatorKey];
[aCoder encodeObject:_title forKey:CPMenuItemTitleKey];
[aCoder encodeObject:_target forKey:CPMenuItemTargetKey];
[aCoder encodeObject:_action forKey:CPMenuItemActionKey];
ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES);
ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES);
ENCODE_IFNOT(CPMenuItemIsHiddenKey, _isHidden, NO);
ENCODE_IFNOT(CPMenuItemTagKey, _tag, 0);
@@ -913,7 +955,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
ENCODE_IFNOT(CPMenuItemImageKey, _image, nil);
ENCODE_IFNOT(CPMenuItemAlternateImageKey, _alternateImage, nil);
ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil);
ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil);
+6 -2
View File
@@ -1,3 +1,6 @@
@import "CPView.j"
var HORIZONTAL_MARGIN = 8.0,
SUBMENU_INDICATOR_MARGIN = 3.0,
VERTICAL_MARGIN = 4.0;
@@ -62,6 +65,7 @@ var SelectionColor = nil,
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(HORIZONTAL_MARGIN, 0.0, 0.0, 0.0)];
[_imageAndTextView setImagePosition:CPImageLeft];
[_imageAndTextView setImageOffset:3.0];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[_imageAndTextView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
@@ -227,8 +231,8 @@ var SelectionColor = nil,
CGContextClosePath(context);
CGContextSetShadowWithColor(context, CGSizeMake(0.0, 1.0), 1.1, _shadowColor);
CGContextSetFillColor(context, _color);
CGContextSetShadowWithColor(context, CGSizeMake(0.0, 1.0), 1.1, _shadowColor || [CPColor whiteColor]);
CGContextSetFillColor(context, _color || [CPColor blackColor]);
CGContextFillPath(context);
}
+1 -1
View File
@@ -1,5 +1,5 @@
@import <AppKit/CPView.j>
@import "CPView.j"
@implementation _CPMenuItemSeparatorView : CPView
+11 -5
View File
@@ -1,3 +1,6 @@
@import "CPControl.j"
var LEFT_MARGIN = 3.0,
RIGHT_MARGIN = 14.0 + 3.0,
STATE_COLUMN_WIDTH = 14.0,
@@ -39,7 +42,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
var bundle = [CPBundle bundleForClass:self];
@@ -257,10 +260,13 @@ var SUBMENU_INDICATOR_COLOR = nil,
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
}
if (shouldHighlight)
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
else
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
if ([[_menuItem menu] showsStateColumn])
{
if (shouldHighlight)
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
else
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
}
}
@end
+4 -2
View File
@@ -1,4 +1,6 @@
@import <AppKit/CPControl.j>
@import "_CPMenuItemSeparatorView.j"
@import "_CPMenuItemStandardView.j"
@import "_CPMenuItemMenuBarView.j"
@@ -43,7 +45,7 @@ var _CPMenuItemSelectionColor = nil,
return;
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
var bundle = [CPBundle bundleForClass:self];
@@ -252,4 +254,4 @@ var _CPMenuItemSelectionColor = nil,
CGContextFillPath(context);
}
@end
@end
+625
View File
@@ -0,0 +1,625 @@
@import <Foundation/CPDictionary.j>
@import <Foundation/CPCountedSet.j>
@import "CPController.j"
@implementation CPObjectController : CPController
{
id _contentObject;
id _selection;
Class _objectClass;
BOOL _isEditable;
BOOL _automaticallyPreparesContent;
CPCountedSet _observedKeys;
}
+ (id)initialize
{
[self exposeBinding:@"editable"];
[self exposeBinding:@"contentObject"];
}
+ (CPSet)keyPathsForValuesAffectingContentObject
{
return [CPSet setWithObjects:"content"];
}
+ (BOOL)automaticallyNotifiesObserversForKey:(CPString)aKey
{
if (aKey === @"contentObject")
return NO;
return YES;
}
+ (CPSet)keyPathsForValuesAffectingCanAdd
{
return [CPSet setWithObject:"editable"];
}
+ (CPSet)keyPathsForValuesAffectingCanInsert
{
return [CPSet setWithObject:"editable"];
}
+ (CPSet)keyPathsForValuesAffectingCanRemove
{
return [CPSet setWithObjects:"editable", "selection"];
}
- (id)init
{
return [self initWithContent:nil];
}
- (id)initWithContent:(id)aContent
{
if (self = [super init])
{
[self setContent:aContent];
[self setEditable:YES];
[self setObjectClass:[CPMutableDictionary class]];
_observedKeys = [[CPCountedSet alloc] init];
}
return self;
}
- (id)content
{
return _contentObject;
}
- (void)setContent:(id)aContent
{
[self willChangeValueForKey:@"contentObject"];
[self _selectionWillChange];
_contentObject = aContent;
[self didChangeValueForKey:@"contentObject"];
[self _selectionDidChange];
}
- (void)_setContentObject:(id)aContent
{
[self setContent:aContent];
}
- (id)_contentObject
{
return [self content];
}
- (void)setAutomaticallyPreparesContent:(BOOL)shouldAutomaticallyPrepareContent
{
_automaticallyPreparesContent = shouldAutomaticallyPrepareContent;
}
- (BOOL)automaticallyPreparesContent
{
return _automaticallyPreparesContent;
}
- (void)prepareContent
{
[self setContent:[self newObject]];
}
- (void)setObjectClass:(Class)aClass
{
_objectClass = aClass;
}
- (Class)objectClass
{
return _objectClass;
}
- (id)newObject
{
return [[[self objectClass] alloc] init];
}
- (void)addObject:(id)anObject
{
[self setContent:anObject];
[[CPKeyValueBinding getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
}
- (void)removeObject:(id)anObject
{
if ([self content] === anObject)
[self setContent:nil];
[[CPKeyValueBinding getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
}
- (void)add:(id)aSender
{
// FIXME: This should happen on the next run loop?
[self addObject:[self newObject]];
}
- (BOOL)canAdd
{
return [self isEditable];
}
- (void)remove:(id)aSender
{
// FIXME: This should happen on the next run loop?
[self removeObject:[self content]];
}
- (BOOL)canRemove
{
return [self isEditable] && [[self selectedObjects] count];
}
- (void)setEditable:(BOOL)shouldBeEditable
{
_isEditable = shouldBeEditable;
}
- (BOOL)isEditable
{
return _isEditable;
}
- (CPArray)selectedObjects
{
return [[_CPObservableArray alloc] initWithObjects:[_contentObject] count:1];
}
- (id)selection
{
return _selection;
}
- (void)_selectionWillChange
{
[_selection controllerWillChange];
[self willChangeValueForKey:@"selection"];
}
- (void)_selectionDidChange
{
if (_selection === undefined || _selection === nil)
_selection = [[CPControllerSelectionProxy alloc] initWithController:self];
[_selection controllerDidChange];
[self didChangeValueForKey:@"selection"];
}
- (id)observedKeys
{
return _observedKeys;
}
- (void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
{
[_observedKeys addObject:aKeyPath];
[super addObserver:anObserver forKeyPath:aKeyPath options:options context:context];
}
- (void)removeObserver:(id)anObserver forKeyPath:(CPString)aKeyPath
{
[_observedKeys removeObject:aKeyPath];
[super removeObserver:anObserver forKeyPath:aKeyPath];
}
@end
var CPObjectControllerObjectClassNameKey = @"CPObjectControllerObjectClassNameKey",
CPObjectControllerIsEditableKey = @"CPObjectControllerIsEditableKey",
CPObjectControllerAutomaticallyPreparesContentKey = @"CPObjectControllerAutomaticallyPreparesContentKey";
@implementation CPObjectController (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
var objectClassName = [aCoder decodeObjectForKey:CPObjectControllerObjectClassNameKey],
objectClass = CPClassFromString(objectClassName);
// FIXME: Error if objectClass === nil
[self setObjectClass:objectClass];
[self setEditable:[aCoder decodeBoolForKey:CPObjectControllerIsEditableKey]];
[self setAutomaticallyPreparesContent:[aCoder decodeBoolForKey:CPObjectControllerAutomaticallyPreparesContentKey] || NO];
_observedKeys = [[CPCountedSet alloc] init];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:CPStringFromClass(objectClass) forKey:CPObjectControllerObjectClassNameKey];
[aCoder encodeObject:[self isEditable] forKey:CPObjectControllerIsEditableKey];
if (![self automaticallyPreparesContent])
[aCoder encodeBOOL:YES forKey:CPObjectControllerAutomaticallyPreparesContentKey];
}
@end
@implementation _CPObservationProxy : CPObject
{
id _keyPath;
id _observer;
id _object;
BOOL _notifyObject;
id _context;
int _options;
}
- (id)initWithKeyPath:(id)aKeyPath observer:(id)anObserver object:(id)anObject
{
if (self=[super init])
{
_keyPath = aKeyPath;
_observer = anObserver;
_object = anObject;
}
return self;
}
- (id)observer
{
return _observer;
}
- (id)keyPath
{
return _keyPath;
}
- (id)context
{
return _context;
}
- (int)options
{
return _options;
}
- (void)setNotifyObject:(BOOL)notify
{
_notifyObject = notify;
}
- (BOOL)isEqual:(id)anObject
{
if ([anObject class] === [self class])
{
if (anObject._observer === _observer && [anObject._keyPath isEqual:_keyPath] && [anObject._object isEqual:_object])
return YES;
}
return NO;
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)change context:(id)context
{
if (_notifyObject)
[_object observeValueForKeyPath:_keyPath ofObject:_object change:change context:context];
[_observer observeValueForKeyPath:_keyPath ofObject:_object change:change context:context];
}
- (CPString)description
{
return [super description] + [CPString stringWithFormat:@"observation proxy for %@ on key path %@", _observer, _keyPath];
}
@end
@implementation _CPObservableArray : CPMutableArray
{
CPArray _observationProxies;
}
+ (id)alloc
{
var a = [];
a.isa = self;
var ivars = class_copyIvarList(self),
count = ivars.length;
while (count--)
a[ivar_getName(ivars[count])] = nil;
return a;
}
- (CPString)description
{
return "<_CPObservableArray: "+[super description]+" >";
}
- (id)initWithArray:(CPArray)anArray
{
if (self = [super initWithArray:anArray])
{
_observationProxies = [];
}
return self;
}
- (id)initWithObjects:(CPArray)objects count:(unsigned)count
{
if (self = [super initWithObjects:objects count:count])
{
_observationProxies = [];
}
return self;
}
-(void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
{
if (aKeyPath.indexOf("@") === 0)
{
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self];
proxy._options = options;
proxy._context = context;
[_observationProxies addObject:proxy];
var dotIndex = aKeyPath.indexOf("."),
remaining = aKeyPath.substring(dotIndex+1),
indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
[self addObserver:proxy toObjectsAtIndexes:indexes forKeyPath:remaining options:options context:context];
}
else
{
var indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
[self addObserver:anObserver toObjectsAtIndexes:indexes forKeyPath:aKeyPath options:options context:context];
}
}
- (void)removeObserver:(id)anObserver forKeyPath:(CPString)aKeyPath
{
if (aKeyPath.indexOf("@") === 0)
{
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self],
index = [_observationProxies indexOfObject:proxy];
proxy = [_observationProxies objectAtIndex:index];
var dotIndex = aKeyPath.indexOf("."),
remaining = aKeyPath.substring(dotIndex+1),
indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
[self removeObserver:proxy fromObjectsAtIndexes:indexes forKeyPath:remaining];
}
else
{
var indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
[self removeObserver:anObserver fromObjectsAtIndexes:indexes forKeyPath:aKeyPath];
}
}
- (void)insertObject:(id)anObject atIndex:(unsigned)anIndex
{
for (var i=0, count=[_observationProxies count]; i<count; i++)
{
var proxy = [_observationProxies objectAtIndex:i],
keyPath = [proxy keyPath],
operator = keyPath.indexOf(".") === 0;
if (operator)
[self willChangeValueForKey:keyPath];
[anObject addObserver:proxy forKeyPath:keyPath options:[proxy options] context:[proxy context]];
if (operator)
[self didChangeValueForKey:keyPath];
}
[super insertObject:anObject atIndex:anIndex];
}
- (void)removeObjectAtIndex:(unsigned)anIndex
{
for (var i=0, count=[_observationProxies count]; i<count; i++)
{
var proxy = [_observationProxies objectAtIndex:i],
keyPath = [proxy keyPath],
operator = keyPath.indexOf(".") === 0;
if (operator)
[self willChangeValueForKey:keyPath];
[anObject removeObserver:proxy forKeyPath:keyPath];
if (operator)
[self didChangeValueForKey:keyPath];
}
[super removeObjectAtIndex:anIndex];
}
- (_CPObservableArray)objectsAtIndexes:(CPIndexSet)theIndexes
{
return [_CPObservableArray arrayWithArray:[super objectsAtIndexes:theIndexes]];
}
- (void)addObject:(id)anObject
{
[self insertObject:anObject atIndex:[self count]];
}
- (void)removeLastObject
{
[self removeObjectAtIndex:[self count]];
}
- (void)replaceObjectAtIndex:(unsigned)anIndex withObject:(id)anObject
{
var currentObject = [self objectAtIndex:anIndex];
for (var i=0, count=[_observationProxies count]; i<count; i++)
{
var proxy = [_observationProxies objectAtIndex:i],
keyPath = [proxy keyPath],
operator = keyPath.indexOf(".") === 0;
if (operator)
[self willChangeValueForKey:keyPath];
[currentObject removeObserver:proxy forKeyPath:keyPath];
[anObject addObserver:proxy forKeyPath:keyPath options:[proxy options] context:[proxy context]];
if (operator)
[self didChangeValueForKey:keyPath];
}
[super replaceObjectAtIndex:anIndex withObject:anObject];
}
@end
@implementation CPControllerSelectionProxy : CPObject
{
id _controller;
id _keys;
CPDictionary _cachedValues;
CPArray _observationProxies;
}
- (id)initWithController:(id)aController
{
if (self = [super init])
{
_cachedValues = [CPDictionary dictionary];
_observationProxies = [CPArray array];
_controller = aController;
}
return self;
}
- (id)valueForKey:(CPString)aKey
{
var value = [_cachedValues objectForKey:aKey];
if (value !== undefined && value !== nil)
return value;
var allValues = [[_controller selectedObjects] valueForKeyPath:aKey],
count = [allValues count];
if (!count)
value = CPNoSelectionMarker;
else if (count === 1)
value = [allValues objectAtIndex:0];
else
{
if ([_controller alwaysUsesMultipleValuesMarker])
value = CPMultipleValuesMarker;
else
{
value = [allValues objectAtIndex:0];
for (var i=0, count=[allValues count]; i<count && value!=CPMultipleValuesMarker; i++)
{
if (![value isEqual:[allValues objectAtIndex:i]])
value = CPMultipleValuesMarker;
}
}
}
[_cachedValues setValue:value forKey:aKey];
return value;
}
- (unsigned)count
{
return [_cachedValues count];
}
- (id)keyEnumerator
{
return [_cachedValues keyEnumerator];
}
- (void)setValue:(id)aValue forKey:(CPString)aKey
{
[[_controller selectedObjects] setValue:aValue forKey:aKey];
}
-(void)controllerWillChange
{
_keys = [_cachedValues allKeys];
if (!_keys)
return;
for (var i=0, count=_keys.length; i<count; i++)
[self willChangeValueForKey:_keys[i]];
[_cachedValues removeAllObjects];
}
-(void)controllerDidChange
{
[_cachedValues removeAllObjects];
if (!_keys)
return;
for (var i=0, count=_keys.length; i<count; i++)
[self didChangeValueForKey:_keys[i]];
_keys = nil;
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)change context:(id)context
{
[_cachedValues removeObjectForKey:aKeyPath];
}
- (void)addObserver:(id)anObject forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
{
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self];
[proxy setNotifyObject:YES];
[_observationProxies addObject:proxy];
[[_controller selectedObjects] addObserver:proxy forKeyPath:aKeyPath options:options context:context];
}
- (void)removeObserver:(id)anObject forKeyPath:(CPString)aKeyPath
{
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self],
index = [_observationProxies indexOfObject:proxy];
[[_controller selectedObjects] removeObserver:[_observationProxies objectAtIndex:index] forKeyPath:aKeyPath];
[_observationProxies removeObjectAtIndex:index];
}
@end
+1 -1
View File
@@ -1,5 +1,5 @@
@import <AppKit/CPPanel.j>
@import "CPPanel.j"
@implementation CPOpenPanel : CPPanel
+371 -125
View File
@@ -23,8 +23,6 @@
@import "CPTableColumn.j"
@import "CPTableView.j"
#include "CoreGraphics/CGGeometry.h"
CPOutlineViewColumnDidMoveNotification = @"CPOutlineViewColumnDidMoveNotification";
CPOutlineViewColumnDidResizeNotification = @"CPOutlineViewColumnDidResizeNotification";
@@ -50,12 +48,30 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_ = 1 << 10;
var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ = 1 << 1,
CPOutlineViewDelegate_outlineView_shouldSelectItem_ = 1 << 2,
CPOutlineViewDelegate_outlineView_heightOfRowByItem_ = 1 << 3,
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ = 1 << 4,
CPOutlineViewDelegate_outlineView_isGroupItem_ = 1 << 5;
CPOutlineViewDelegate_outlineView_didClickTableColumn_ = 1 << 2,
CPOutlineViewDelegate_outlineView_didDragTableColumn_ = 1 << 3,
CPOutlineViewDelegate_outlineView_heightOfRowByItem_ = 1 << 4,
CPOutlineViewDelegate_outlineView_isGroupItem_ = 1 << 5,
CPOutlineViewDelegate_outlineView_mouseDownInHeaderOfTableColumn_ = 1 << 6,
CPOutlineViewDelegate_outlineView_nextTypeSelectMatchFromItem_toItem_forString_ = 1 << 7,
CPOutlineViewDelegate_outlineView_selectionIndexesForProposedSelection_ = 1 << 8,
CPOutlineViewDelegate_outlineView_shouldCollapseItem_ = 1 << 9,
CPOutlineViewDelegate_outlineView_shouldEditTableColumn_item_ = 1 << 10,
CPOutlineViewDelegate_outlineView_shouldExpandItem_ = 1 << 11,
CPOutlineViewDelegate_outlineView_shouldReorderColumn_toColumn_ = 1 << 12,
CPOutlineViewDelegate_outlineView_shouldSelectItem_ = 1 << 13,
CPOutlineViewDelegate_outlineView_shouldSelectTableColumn_ = 1 << 14,
CPOutlineViewDelegate_outlineView_shouldShowOutlineViewForItem_ = 1 << 15,
CPOutlineViewDelegate_outlineView_shouldShowViewExpansionForTableColumn_item_ = 1 << 16,
CPOutlineViewDelegate_outlineView_shouldTrackView_forTableColumn_item_ = 1 << 17,
CPOutlineViewDelegate_outlineView_shouldTypeSelectForEvent_withCurrentSearchString_ = 1 << 18,
CPOutlineViewDelegate_outlineView_sizeToFitWidthOfColumn_ = 1 << 19,
CPOutlineViewDelegate_outlineView_toolTipForView_rect_tableColumn_item_mouseLocation_ = 1 << 20,
CPOutlineViewDelegate_outlineView_typeSelectStringForTableColumn_item_ = 1 << 21,
CPOutlineViewDelegate_outlineView_willDisplayOutlineView_forTableColumn_item_ = 1 << 22,
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ = 1 << 23,
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ = 1 << 24;
CPOutlineViewDropOnItemIndex = -1;
@@ -79,12 +95,14 @@ CPOutlineViewDropOnItemIndex = -1;
CPArray _disclosureControlsForRows;
CPData _disclosureControlData;
CPArray _disclosureControlQueue;
BOOL _shouldRetargetItem;
id _retargetedItem;
BOOL _shouldRetargetChildIndex;
CPInteger _retargedChildIndex;
CPTimer _dragHoverTimer;
id _dropItem;
}
- (id)initWithFrame:(CGRect)aFrame
@@ -105,9 +123,10 @@ CPOutlineViewDropOnItemIndex = -1;
_retargetedItem = nil;
_shouldRetargetItem = NO;
_retargedChildIndex = nil;
_shouldRetargetChildIndex = NO;
_startHoverTime = nil;
[self setIndentationPerLevel:16.0];
[self setIndentationMarkerFollowsDataView:YES];
@@ -213,7 +232,7 @@ CPOutlineViewDropOnItemIndex = -1;
- (void)expandItem:(id)anItem expandChildren:(BOOL)shouldExpandChildren
{
var itemInfo = null;
if (!anItem)
itemInfo = _rootItemInfo;
else
@@ -221,15 +240,21 @@ CPOutlineViewDropOnItemIndex = -1;
if (!itemInfo)
return;
itemInfo.isExpanded = YES;
[self reloadItem:anItem reloadChildren:YES];
// to prevent items which are already expanded from firing notifications
if (!itemInfo.isExpanded)
{
[self _noteItemWillExpand:anItem];
itemInfo.isExpanded = YES;
[self _noteItemDidExpand:anItem];
[self reloadItem:anItem reloadChildren:YES];
}
if (shouldExpandChildren)
{
var children = itemInfo.children,
childIndex = children.length;
while (childIndex--)
[self expandItem:children[childIndex] expandChildren:YES];
}
@@ -248,7 +273,9 @@ CPOutlineViewDropOnItemIndex = -1;
if (!itemInfo.isExpanded)
return;
[self _noteItemWillCollapse:anItem];
itemInfo.isExpanded = NO;
[self _noteItemDidCollapse:anItem];
[self reloadItem:anItem reloadChildren:YES];
}
@@ -363,7 +390,7 @@ CPOutlineViewDropOnItemIndex = -1;
return nil;
var parent = itemInfo.parent;
// Check if the parent is the root item because we never return the actual root item
if (itemInfo[[parent UID]] === _rootItemInfo)
parent = nil;
@@ -382,43 +409,14 @@ CPOutlineViewDropOnItemIndex = -1;
return frame;
}
- (void)selectRowIndexes:(CPIndexSet)rows byExtendingSelection:(BOOL)shouldExtendSelection
- (void)_performSelection:(BOOL)select forRow:(CPInteger)rowIndex context:(id)context
{
// First un highlight the old disclosure controls
var previousSelectedRows = [];
[[self selectedRowIndexes] getIndexes:previousSelectedRows maxCount:-1 inIndexRange:nil];
var index = [previousSelectedRows count];
while (index--)
{
var rowIndex = previousSelectedRows[index],
item = [self itemAtRow:rowIndex];
if (![self isExpandable:item])
continue;
var control = _disclosureControlsForRows[rowIndex];
[control setHighlighted:NO];
}
[super selectRowIndexes:rows byExtendingSelection:shouldExtendSelection];
// Now highlight the new disclosure controls
var selectedRows = [];
[rows getIndexes:selectedRows maxCount:-1 inIndexRange:nil];
var index = [selectedRows count];
while (index--)
{
var rowIndex = selectedRows[index],
item = [self itemAtRow:rowIndex];
if (![self isExpandable:item])
continue;
var control = _disclosureControlsForRows[rowIndex];
[control setHighlighted:YES];
}
[super _performSelection:select forRow:rowIndex context:context];
var control = _disclosureControlsForRows[rowIndex],
selector = select ? @"setThemeState:" : @"unsetThemeState:";
[control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected];
}
- (void)setDelegate:(id)aDelegate
@@ -453,25 +451,76 @@ CPOutlineViewDropOnItemIndex = -1;
removeObserver:_outlineViewDelegate
name:CPOutlineViewSelectionIsChangingNotification
object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillExpand:)])
[defaultCenter
removeObserver:_outlineViewDelegate
name:CPOutlineViewItemWillExpandNotification
object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidExpand:)])
[defaultCenter
removeObserver:_outlineViewDelegate
name:CPOutlineViewItemDidExpandNotification
object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillCollapse:)])
[defaultCenter
removeObserver:_outlineViewDelegate
name:CPOutlineViewItemWillCollapseNotification
object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidCollapse:)])
[defaultCenter
removeObserver:_outlineViewDelegate
name:CPOutlineViewItemDidCollapseNotification
object:self];
}
_outlineViewDelegate = aDelegate;
_implementedOutlineViewDelegateMethods = 0;
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:dataViewForTableColumn:item:)])
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_;
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:shouldSelectItem:)])
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_shouldSelectItem_;
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:heightOfRowByItem:)])
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_heightOfRowByItem_;
var delegateMethods = [
CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ , @selector(outlineView:dataViewForTableColumn:item:),
CPOutlineViewDelegate_outlineView_didClickTableColumn_ , @selector(outlineView:didClickTableColumn:),
CPOutlineViewDelegate_outlineView_didDragTableColumn_ , @selector(outlineView:didDragTableColumn:),
CPOutlineViewDelegate_outlineView_heightOfRowByItem_ , @selector(outlineView:heightOfRowByItem:),
CPOutlineViewDelegate_outlineView_isGroupItem_ , @selector(outlineView:isGroupItem:),
CPOutlineViewDelegate_outlineView_mouseDownInHeaderOfTableColumn_ , @selector(outlineView:mouseDownInHeaderOfTableColumn:),
CPOutlineViewDelegate_outlineView_nextTypeSelectMatchFromItem_toItem_forString_ , @selector(outlineView:nextTypeSelectMatchFromItem:toItem:forString:),
CPOutlineViewDelegate_outlineView_selectionIndexesForProposedSelection_ , @selector(outlineView:selectionIndexesForProposedSelection:),
CPOutlineViewDelegate_outlineView_shouldCollapseItem_ , @selector(outlineView:shouldCollapseItem:),
CPOutlineViewDelegate_outlineView_shouldEditTableColumn_item_ , @selector(outlineView:shouldEditTableColumn:item:),
CPOutlineViewDelegate_outlineView_shouldExpandItem_ , @selector(outlineView:shouldExpandItem:),
CPOutlineViewDelegate_outlineView_shouldReorderColumn_toColumn_ , @selector(outlineView:shouldReorderColumn:toColumn:),
CPOutlineViewDelegate_outlineView_shouldSelectItem_ , @selector(outlineView:shouldSelectItem:),
CPOutlineViewDelegate_outlineView_shouldSelectTableColumn_ , @selector(outlineView:shouldSelectTableColumn:),
CPOutlineViewDelegate_outlineView_shouldShowOutlineViewForItem_ , @selector(outlineView:shouldShowOutlineViewForItem:),
CPOutlineViewDelegate_outlineView_shouldShowViewExpansionForTableColumn_item_ , @selector(outlineView:shouldShowViewExpansionForTableColumn:item:),
CPOutlineViewDelegate_outlineView_shouldTrackView_forTableColumn_item_ , @selector(outlineView:shouldTrackView:forTableColumn:item:),
CPOutlineViewDelegate_outlineView_shouldTypeSelectForEvent_withCurrentSearchString_ , @selector(outlineView:shouldTypeSelectForEvent:withCurrentSearchString:),
CPOutlineViewDelegate_outlineView_sizeToFitWidthOfColumn_ , @selector(outlineView:sizeToFitWidthOfColumn:),
CPOutlineViewDelegate_outlineView_toolTipForView_rect_tableColumn_item_mouseLocation_, @selector(outlineView:toolTipForView:rect:tableColumn:item:mouseLocation:),
CPOutlineViewDelegate_outlineView_typeSelectStringForTableColumn_item_ , @selector(outlineView:typeSelectStringForTableColumn:item:),
CPOutlineViewDelegate_outlineView_willDisplayOutlineView_forTableColumn_item_ , @selector(outlineView:willDisplayOutlineView:forTableColumn:item:),
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ , @selector(outlineView:willDisplayView:forTableColumn:item:),
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ , @selector(selectionShouldChangeInOutlineView:)
],
delegateCount = [delegateMethods count];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:willDisplayView:forTableColumn:item:)])
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_;
for (var i=0; i < delegateCount; i += 2)
{
var bitMask = delegateMethods[i],
selector = delegateMethods[i+1];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:isGroupItem:)])
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_isGroupItem_;
if ([_outlineViewDelegate respondsToSelector:selector])
_implementedOutlineViewDelegateMethods |= bitMask;
}
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidMove:)])
[defaultCenter
@@ -500,6 +549,36 @@ CPOutlineViewDropOnItemIndex = -1;
selector:@selector(outlineViewSelectionIsChanging:)
name:CPOutlineViewSelectionIsChangingNotification
object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillExpand:)])
[defaultCenter
addObserver:_outlineViewDelegate
selector:@selector(outlineViewItemWillExpand:)
name:CPOutlineViewItemWillExpandNotification
object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidExpand:)])
[defaultCenter
addObserver:_outlineViewDelegate
selector:@selector(outlineViewItemDidExpand:)
name:CPOutlineViewItemDidExpandNotification
object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillCollapse:)])
[defaultCenter
addObserver:_outlineViewDelegate
selector:@selector(outlineViewItemWillCollapse:)
name:CPOutlineViewItemWillCollapseNotification
object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidCollapse:)])
[defaultCenter
addObserver:_outlineViewDelegate
selector:@selector(outlineViewItemDidCollapse:)
name:CPOutlineViewItemDidCollapseNotification
object:self];
}
- (id)delegate
@@ -534,18 +613,63 @@ CPOutlineViewDropOnItemIndex = -1;
- (void)setDropItem:(id)theItem dropChildIndex:(int)theIndex
{
if (_dropItem !== theItem && theIndex < 0 && [self isExpandable:theItem] && ![self isItemExpanded:theItem])
{
if (_dragHoverTimer)
[_dragHoverTimer invalidate];
var autoExpandCallBack = function(){
if (_dropItem)
{
[_dropOperationFeedbackView blink];
[CPTimer scheduledTimerWithTimeInterval:.3 callback:objj_msgSend(self, "expandItem:", _dropItem) repeats:NO];
}
}
_dragHoverTimer = [CPTimer scheduledTimerWithTimeInterval:.8 callback:autoExpandCallBack repeats:NO];
}
if (theIndex >= 0)
{
[_dragHoverTimer invalidate];
_dragHoverTimer = nil;
}
_dropItem = theItem;
_retargetedItem = theItem;
_shouldRetargetItem = YES;
_retargedChildIndex = theIndex;
_shouldRetargetChildIndex = YES;
// set CPTableView's _retargetedDropRow based on retargetedItem and retargetedChildIndex
var retargetedItemInfo = (_retargetedItem !== nil) ? _itemInfosForItems[[_retargetedItem UID]] : _rootItemInfo;
if (_retargedChildIndex === [retargetedItemInfo.children count])
{
var retargetedChildItem = [retargetedItemInfo.children lastObject];
_retargetedDropRow = [self rowForItem:retargetedChildItem] + 1;
}
else
{
var retargetedChildItem = (_retargedChildIndex !== CPOutlineViewDropOnItemIndex) ? retargetedItemInfo.children[_retargedChildIndex] : _retargetedItem;
_retargetedDropRow = [self rowForItem:retargetedChildItem];
}
}
- (void)_draggingEnded
{
[super _draggingEnded];
_dropItem = nil;
[_dragHoverTimer invalidate];
_dragHoverTimer = nil;
}
- (id)_parentItemForUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex atMouseOffset:(CPPoint)theOffset
{
if (_shouldRetargetItem)
return _retargetedItem;
var lowerLevel = [self levelForRow:theLowerRowIndex]
upperItem = [self itemAtRow:theUpperRowIndex];
upperLevel = [self levelForItem:upperItem];
@@ -564,7 +688,7 @@ CPOutlineViewDropOnItemIndex = -1;
// Check the next parent
upperItem = [self parentForItem:upperItem];
}
return [self parentForItem:[self itemAtRow:theLowerRowIndex]];
}
@@ -574,10 +698,10 @@ CPOutlineViewDropOnItemIndex = -1;
var rect = [super _rectForDropHighlightViewBetweenUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex offset:theOffset],
parentItem = [self _parentItemForUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex atMouseOffset:theOffset],
level = [self levelForItem:parentItem];
rect.origin.x = (level + 1) * [self indentationPerLevel];
rect.origin.x = (level + 1) * [self indentationPerLevel];
rect.size.width -= rect.origin.x; // This assumes that the x returned by super is zero
return rect;
}
@@ -619,6 +743,8 @@ CPOutlineViewDropOnItemIndex = -1;
_disclosureControlsForRows[row] = control;
[control setState:[self isItemExpanded:item] ? CPOnState : CPOffState];
var selector = [self isRowSelected:row] ? @"setThemeState:" : @"unsetThemeState:";
[control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected];
[control setFrame:frame];
[self addSubview:control];
@@ -709,9 +835,41 @@ CPOutlineViewDropOnItemIndex = -1;
userInfo:nil];
}
- (void)_noteItemWillExpand:(id)item
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewItemWillExpandNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
}
- (void)_noteItemDidExpand:(id)item
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewItemDidExpandNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
}
- (void)_noteItemWillCollapse:(id)item
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewItemWillCollapseNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
}
- (void)_noteItemDidCollapse:(id)item
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewItemDidCollapseNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
}
@end
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
{
if (!anItem)
@@ -724,55 +882,55 @@ var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
dataSource = _outlineViewDataSource,
itemUID = [anItem UID],
itemInfo = itemInfosForItems[itemUID];
// If we're not in the tree, then just bail.
if (!itemInfo)
return [];
// See if the item itself can be swapped out.
var parent = itemInfo.parent,
parentItemInfo = parent ? itemInfosForItems[[parent UID]] : _rootItemInfo,
parentChildren = parentItemInfo.children,
index = [parentChildren indexOfObjectIdenticalTo:anItem],
newItem = [dataSource outlineView:anOutlineView child:index ofItem:parent];
if (anItem !== newItem)
{
itemInfosForItems[[anItem UID]] = nil;
itemInfosForItems[[newItem UID]] = itemInfo;
parentChildren[index] = newItem;
_itemsForRows[itemInfo.row] = newItem;
}
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem];
itemInfo.isExpanded = itemInfo.isExpandable && itemInfo.isExpanded;
}
}
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem, /*BOOL*/ isIntermediate)
{
with(anOutlineView)
{
var itemInfosForItems = _itemInfosForItems,
dataSource = _outlineViewDataSource;
if (!anItem)
var itemInfo = _rootItemInfo;
else
{
// Get the existing info if it exists.
var itemUID = [anItem UID],
itemInfo = itemInfosForItems[itemUID];
// If we're not in the tree, then just bail.
if (!itemInfo)
return [];
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:anItem];
// If we were previously expanded, but now no longer expandable, "de-expand".
// NOTE: we are *not* collapsing, thus no notification is posted.
if (!itemInfo.isExpandable && itemInfo.isExpanded)
@@ -781,72 +939,72 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
itemInfo.children = [];
}
}
// The root item does not count as a descendant.
var weight = itemInfo.weight,
descendants = anItem ? [anItem] : [];
if (itemInfo.isExpanded && (!(_implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_) ||
![dataSource outlineView:anOutlineView shouldDeferDisplayingChildrenOfItem:anItem]))
{
var index = 0,
count = [dataSource outlineView:anOutlineView numberOfChildrenOfItem:anItem],
level = itemInfo.level + 1;
itemInfo.children = [];
for (; index < count; ++index)
{
var childItem = [dataSource outlineView:anOutlineView child:index ofItem:anItem],
childItemInfo = itemInfosForItems[[childItem UID]];
if (!childItemInfo)
{
childItemInfo = { isExpanded:NO, isExpandable:NO, children:[], weight:1 };
itemInfosForItems[[childItem UID]] = childItemInfo;
}
itemInfo.children[index] = childItem;
var childDescendants = _loadItemInfoForItem(anOutlineView, childItem, YES);
childItemInfo.parent = anItem;
childItemInfo.level = level;
descendants = descendants.concat(childDescendants);
}
}
itemInfo.weight = descendants.length;
if (!isIntermediate)
{
// row = -1 is the root item, so just go to row 0 since it is ignored.
var index = MAX(itemInfo.row, 0),
itemsForRows = _itemsForRows;
descendants.unshift(index, weight);
itemsForRows.splice.apply(itemsForRows, descendants);
var count = itemsForRows.length;
for (; index < count; ++index)
itemInfosForItems[[itemsForRows[index] UID]].row = index;
var deltaWeight = itemInfo.weight - weight;
if (deltaWeight !== 0)
{
var parent = itemInfo.parent;
while (parent)
{
var parentItemInfo = itemInfosForItems[[parent UID]];
parentItemInfo.weight += deltaWeight;
parent = parentItemInfo.parent;
}
if (anItem)
_rootItemInfo.weight += deltaWeight;
}
@@ -880,20 +1038,27 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
return [_outlineView._outlineViewDataSource outlineView:_outlineView objectValueForTableColumn:aTableColumn byItem:_outlineView._itemsForRows[aRow]];
}
- (void)tableView:(CPTableView)aTableView setObjectValue:(id)aValue forTableColumn:(CPTableColumn)aColumn row:(CPInteger)aRow
{
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_))
return;
[_outlineView._outlineViewDataSource outlineView:_outlineView setObjectValue:aValue forTableColumn:aColumn byItem:_outlineView._itemsForRows[aRow]];
}
- (BOOL)tableView:(CPTableView)aTableColumn writeRowsWithIndexes:(CPIndexSet)theIndexes toPasteboard:(CPPasteboard)thePasteboard
{
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_))
return NO;
var rowIndexes = [];
[theIndexes getIndexes:rowIndexes maxCount:[theIndexes count] inIndexRange:nil];
var rowIndex = [rowIndexes count],
items = [];
while (rowIndex--)
[items addObject:[_outlineView itemAtRow:[rowIndexes objectAtIndex:rowIndex]]];
return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard];
}
@@ -901,15 +1066,15 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
{
if (_outlineView._shouldRetargetChildIndex)
return _outlineView._retargedChildIndex;
var childIndex = CPNotFound;
if (theDropOperation === CPTableViewDropAbove)
{
var parentItem = [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset],
itemInfo = (parentItem !== nil) ? _outlineView._itemInfosForItems[[parentItem UID]] : _outlineView._rootItemInfo,
children = itemInfo.children;
childIndex = [children indexOfObject:[_outlineView itemAtRow:theRow]];
if (childIndex === CPNotFound)
@@ -924,12 +1089,12 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
- (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)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];
}
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id < CPDraggingInfo >)theInfo
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id < CPDraggingInfo >)theInfo
proposedRow:(int)theRow proposedDropOperation:(CPTableViewDropOperation)theOperation
{
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_))
@@ -943,21 +1108,21 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
_outlineView._shouldRetargetChildIndex = NO;
var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil],
parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location];
parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location],
childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
return [_outlineView._outlineViewDataSource outlineView:_outlineView validateDrop:theInfo proposedItem:parentItem proposedChildIndex:childIndex];
}
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id <CPDraggingInfo>)theInfo row:(int)theRow dropOperation:(CPTableViewDropOperation)theOperation
{
{
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_))
return NO;
var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil],
parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location];
childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
_outlineView._retargetedItem = nil;
_outlineView._shouldRetargetItem = NO;
@@ -987,15 +1152,15 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
- (CPView)tableView:(CPTableView)theTableView dataViewForTableColumn:(CPTableColumn)theTableColumn row:(int)theRow
{
var dataView = nil;
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_))
dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView
dataViewForTableColumn:theTableColumn
dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView
dataViewForTableColumn:theTableColumn
item:[_outlineView itemAtRow:theRow]];
if (!dataView)
dataView = [theTableColumn dataViewForRow:theRow];
dataView = [theTableColumn dataViewForRow:theRow];
return dataView;
}
@@ -1003,10 +1168,18 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
{
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_))
return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldSelectItem:[_outlineView itemAtRow:theRow]];
return YES;
}
- (BOOL)tableView:(CPTableView)aTableView shouldEditTableColumn:(CPTableColumn)aColumn row:(int)aRow
{
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldEditTableColumn_item_))
return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldEditTableColumn:aColumn item:[_outlineView itemAtRow:aRow]];
return NO;
}
- (float)tableView:(CPTableView)theTableView heightOfRow:(int)theRow
{
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_heightOfRowByItem_))
@@ -1024,10 +1197,10 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
}
}
- (BOOL)tableView:(CPTableView)aTableView isGroupRow:(int)row
- (BOOL)tableView:(CPTableView)aTableView isGroupRow:(int)aRow
{
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_isGroupItem_))
return [_outlineView._outlineViewDelegate outlineView:_outlineView isGroupItem:[_outlineView itemAtRow:theRow]];
return [_outlineView._outlineViewDelegate outlineView:_outlineView isGroupItem:[_outlineView itemAtRow:aRow]];
return NO;
}
@@ -1080,9 +1253,82 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
CGContextAddLineToPoint(context, 0.0, 0.0);
CGContextClosePath(context);
CGContextSetFillColor(context, [self isHighlighted] ? [CPColor whiteColor] : [CPColor grayColor]);
CGContextSetFillColor(context,
colorForDisclosureTriangle([self hasThemeState:CPThemeStateSelected],
[self hasThemeState:CPThemeStateHighlighted]));
CGContextFillPath(context);
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0.0, 0.0);
if(_angle === 0.0) {
CGContextAddLineToPoint(context, 4.5, 8.0);
CGContextAddLineToPoint(context, 9.0, 0.0);
} else {
CGContextAddLineToPoint(context, 4.5, 8.0);
}
CGContextSetStrokeColor(context, [CPColor colorWithCalibratedWhite:1.0 alpha: 0.8]);
CGContextStrokePath(context);
}
@end
var CPOutlineViewIndentationPerLevelKey = @"CPOutlineViewIndentationPerLevelKey",
CPOutlineViewOutlineTableColumnKey = @"CPOutlineViewOutlineTableColumnKey",
CPOutlineViewDataSourceKey = @"CPOutlineViewDataSourceKey",
CPOutlineViewDelegateKey = @"CPOutlineViewDelegateKey";
@implementation CPOutlineView (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
// The root item has weight "0", thus represents the weight solely of its descendants.
_rootItemInfo = { isExpanded:YES, isExpandable:NO, level:-1, row:-1, children:[], weight:0 };
_itemsForRows = [];
_itemInfosForItems = { };
_disclosureControlsForRows = [];
[self setIndentationMarkerFollowsDataView:YES];
[self setDisclosureControlPrototype:[[CPDisclosureButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)]];
_outlineTableColumn = [aCoder decodeObjectForKey:CPOutlineViewOutlineTableColumnKey];
_indentationPerLevel = [aCoder decodeFloatForKey:CPOutlineViewIndentationPerLevelKey];
_outlineViewDataSource = [aCoder decodeObjectForKey:CPOutlineViewDataSourceKey];
_outlineViewDelegate = [aCoder decodeObjectForKey:CPOutlineViewDelegateKey];
[super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_outlineTableColumn forKey:CPOutlineViewOutlineTableColumnKey];
[aCoder encodeFloat:_indentationPerLevel forKey:CPOutlineViewIndentationPerLevelKey];
[aCoder encodeObject:_outlineViewDataSource forKey:CPOutlineViewDataSourceKey];
[aCoder encodeObject:_outlineViewDelegate forKey:CPOutlineViewDelegateKey];
}
@end
var colorForDisclosureTriangle = function(isSelected, isHighlighted) {
return isSelected
? (isHighlighted
? [CPColor colorWithCalibratedWhite:0.9 alpha: 1.0]
: [CPColor colorWithCalibratedWhite:1.0 alpha: 1.0])
: (isHighlighted
? [CPColor colorWithCalibratedWhite:0.4 alpha: 1.0]
: [CPColor colorWithCalibratedWhite:0.5 alpha: 1.0]);
}
-2
View File
@@ -25,8 +25,6 @@
@import <Foundation/CPDictionary.j>
@import <Foundation/CPPropertyListSerialization.j>
#include "Platform/Platform.h"
CPGeneralPboard = @"CPGeneralPboard";
CPFontPboard = @"CPFontPboard";
+65 -41
View File
@@ -25,14 +25,12 @@
@import "CPMenu.j"
@import "CPMenuItem.j"
#include "CoreGraphics/CGGeometry.h"
var VISIBLE_MARGIN = 7.0;
CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
/*!
/*!
@ingroup appkit
@class CPPopUpButton
@@ -42,11 +40,11 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{
int _selectedIndex;
CPRectEdge _preferredEdge;
CPMenu _menu;
}
+ (CPString)themeClass
+ (CPString)defaultThemeClass
{
return "popup-button";
}
@@ -60,21 +58,21 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
- (id)initWithFrame:(CGRect)aFrame pullsDown:(BOOL)shouldPullDown
{
self = [super initWithFrame:aFrame];
if (self)
{
_selectedIndex = CPNotFound;
_preferredEdge = CPMaxYEdge;
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
[self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"];
[self setValue:CPLineBreakByTruncatingTail forThemeAttribute:@"line-break-mode"];
[self setMenu:[[CPMenu alloc] initWithTitle:@""]];
[self setPullsDown:shouldPullDown];
}
return self;
}
@@ -145,7 +143,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{
var index = 0,
count = [titles count];
for (; index < count; ++index)
[self addItemWithTitle:titles[index]];
}
@@ -159,11 +157,11 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{
var items = [self itemArray],
count = [items count];
while (count--)
if ([items[count] title] == aTitle)
[self removeItemAtIndex:count];
[_menu insertItemWithTitle:aTitle action:NULL keyEquivalent:nil atIndex:anIndex];
}
@@ -173,7 +171,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
- (void)removeAllItems
{
var count = [_menu numberOfItems];
while (count--)
[_menu removeItemAtIndex:0];
}
@@ -206,7 +204,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{
if (_selectedIndex < 0 || _selectedIndex > [self numberOfItems] - 1)
return nil;
return [_menu itemAtIndex:_selectedIndex];
}
@@ -253,15 +251,15 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{
if (_selectedIndex == anIndex)
return;
if (_selectedIndex >= 0 && ![self pullsDown])
[[self selectedItem] setState:CPOffState];
_selectedIndex = anIndex;
if (_selectedIndex >= 0 && ![self pullsDown])
[[self selectedItem] setState:CPOnState];
[self synchronizeTitleAndSelectedItem];
}
@@ -310,7 +308,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
return;
var defaultCenter = [CPNotificationCenter defaultCenter];
if (_menu)
{
[defaultCenter
@@ -330,7 +328,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
}
_menu = aMenu;
if (_menu)
{
[defaultCenter
@@ -338,20 +336,20 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
selector:@selector(menuDidAddItem:)
name:CPMenuDidAddItemNotification
object:_menu];
[defaultCenter
addObserver:self
selector:@selector(menuDidChangeItem:)
name:CPMenuDidChangeItemNotification
object:_menu];
[defaultCenter
addObserver:self
selector:@selector(menuDidRemoveItem:)
name:CPMenuDidRemoveItemNotification
object:_menu];
}
[self synchronizeTitleAndSelectedItem];
}
@@ -396,12 +394,13 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{
var titles = [],
items = [self itemArray],
index = 0,
count = [items count];
for (; index < count; ++index)
items.push([items[index] title]);
titles.push([items[index] title]);
return titles;
}
/*!
@@ -519,14 +518,14 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
else
{
var index = [self indexOfItemWithTitle:aTitle];
if (index < 0)
{
[self addItemWithTitle:aTitle];
index = [self numberOfItems] - 1;
}
[self selectItemAtIndex:index];
}
}
@@ -554,7 +553,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if ([self pullsDown])
{
var items = [_menu itemArray];
if ([items count] > 0)
item = items[0];
}
@@ -573,22 +572,22 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
- (void)menuDidAddItem:(CPNotification)aNotification
{
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"];
if (_selectedIndex < 0)
[self selectItemAtIndex:0];
else if (index == _selectedIndex)
[self synchronizeTitleAndSelectedItem];
else if (index < _selectedIndex)
++_selectedIndex;
if (index == 0 && [self pullsDown])
{
var items = [_menu itemArray];
[items[0] setHidden:YES];
if (items.length > 0)
[items[1] setHidden:NO];
}
@@ -613,10 +612,10 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if ([self pullsDown] && index != 0)
return;
if (![self pullsDown] && index != _selectedIndex)
return;
[self synchronizeTitleAndSelectedItem];
}
@@ -627,7 +626,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
- (void)menuDidRemoveItem:(CPNotification)aNotification
{
var numberOfItems = [self numberOfItems];
if (numberOfItems <= _selectedIndex && numberOfItems > 0)
[self selectItemAtIndex:numberOfItems - 1];
else
@@ -661,6 +660,9 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0);
minimumWidth += standardLeftMargin;
// To ensure the selected item is highlighted correctly, unset the highlighted item
[menu _highlightItemAtIndex:CPNotFound];
}
[menu setMinimumWidth:minimumWidth];
@@ -698,11 +700,33 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
}
- (void)rightMouseDown:(CPEvent)anEvent
{
// Disable standard CPView behaviour which incorrectly displays the menu as a 'context menu'.
}
- (void)_popUpItemAction:(id)aSender
{
[self sendAction:[self action] to:[self target]];
}
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
var count = objects.length,
value = [objects[0] valueForKeyPath:aKeyPath];
[self selectItemWithTag:value];
[self setEnabled:YES];
while (count-- > 1)
{
if (value !== [objects[count] valueForKeyPath:aKeyPath])
{
[[self selectedItem] setState:CPOffState];
}
}
}
@end
var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
@@ -720,7 +744,7 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
// Nothing is currently selected
@@ -729,7 +753,7 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
[self setMenu:[aCoder decodeObjectForKey:CPPopUpButtonMenuKey]];
[self selectItemAtIndex:[aCoder decodeObjectForKey:CPPopUpButtonSelectedIndexKey]];
}
return self;
}
@@ -741,7 +765,7 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_menu forKey:CPPopUpButtonMenuKey];
[aCoder encodeInt:_selectedIndex forKey:CPPopUpButtonSelectedIndexKey];
}
+3 -5
View File
@@ -20,11 +20,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <AppKit/CGGeometry.j>
@import <AppKit/CPImageView.j>
@import <AppKit/CPView.j>
#include "CoreGraphics/CGGeometry.h"
@import "CGGeometry.j"
@import "CPImageView.j"
@import "CPView.j"
/*
+19 -15
View File
@@ -25,28 +25,29 @@
@import "CPButton.j"
/*!
@ingroup appkit
from this mailing list thread:
http://groups.google.com/group/objectivej/browse_thread/thread/7c41cbd9cbee9ea3
http://groups.google.com/group/objectivej/browse_thread/thread/7c41cbd9cbee9ea3
-----------------------------------
Creating a checkbox is easy enough:
checkbox = [[CPCheckBox alloc] initWithFrame:aFrame];
That's basically all there is to it. Radio buttons are very similar,
the key difference is the introduction of a new class CPRadioGroup,
which defines which radio buttons are part of the same group:
[myRadioButton setRadioGroup:aRadioGroup];
Every radio button receives a unique radio group by default (so if you
do nothing further, they will all behave independently), but you can
use an existing radio button's group with other buttons as so:
button1 = [[CPRadio alloc] initWithFrame:aFrame];
...
button2 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1
@@ -55,13 +56,16 @@
button3 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1
radioGroup]];
...etc...
Here, all the radio buttons will act "together". [[button1 radioGroup]
allRadios] returns every button that's part of this group, and
[[button1 radioGroup] selectedRadio] returns the currently selected
option.
*/
CPRadioImageOffset = 4.0;
@implementation CPRadio : CPButton
{
CPRadioGroup _radioGroup;
@@ -86,7 +90,7 @@
return button;
}
+ (CPString)themeClass
+ (CPString)defaultThemeClass
{
return @"radio";
}
@@ -95,7 +99,7 @@
- (id)initWithFrame:(CGRect)aFrame radioGroup:(CPRadioGroup)aRadioGroup
{
self = [super initWithFrame:aFrame];
if (self)
{
[self setRadioGroup:aRadioGroup];
@@ -109,8 +113,8 @@
[self setBordered:YES];
}
return self;
return self;
}
- (id)initWithFrame:(CGRect)aFrame
@@ -141,7 +145,7 @@
- (void)setObjectValue:(id)aValue
{
[super setObjectValue:aValue];
if ([self state] === CPOnState)
[_radioGroup _setSelectedRadio:self];
}
+65 -53
View File
@@ -23,22 +23,23 @@
@import <Foundation/CPObject.j>
CPDeleteKeyCode = 8;
CPTabKeyCode = 9;
CPReturnKeyCode = 13;
CPEscapeKeyCode = 27;
CPSpaceKeyCode = 32;
CPPageUpKeyCode = 33;
CPPageDownKeyCode = 34;
CPLeftArrowKeyCode = 37;
CPUpArrowKeyCode = 38;
CPRightArrowKeyCode = 39;
CPDownArrowKeyCode = 40;
CPDeleteKeyCode = 8;
CPTabKeyCode = 9;
CPReturnKeyCode = 13;
CPEscapeKeyCode = 27;
CPSpaceKeyCode = 32;
CPPageUpKeyCode = 33;
CPPageDownKeyCode = 34;
CPLeftArrowKeyCode = 37;
CPUpArrowKeyCode = 38;
CPRightArrowKeyCode = 39;
CPDownArrowKeyCode = 40;
CPDeleteForwardKeyCode = 46;
/*!
@ingroup appkit
@class CPResponder
Subclasses of CPResonder can be part of the responder chain.
*/
@implementation CPResponder : CPObject
@@ -104,42 +105,24 @@ CPDownArrowKeyCode = 40;
for (; index < count; ++index)
{
var event = events[index];
var event = events[index],
modifierFlags = [event modifierFlags],
character = [event charactersIgnoringModifiers],
selectorNames = [CPKeyBinding selectorsForKey:character modifierFlags:modifierFlags];
switch([event keyCode])
if (selectorNames)
{
case CPPageUpKeyCode: [self doCommandBySelector:@selector(pageUp:)];
break;
case CPPageDownKeyCode: [self doCommandBySelector:@selector(pageDown:)];
break;
case CPLeftArrowKeyCode: [self doCommandBySelector:@selector(moveLeft:)];
break;
case CPRightArrowKeyCode: [self doCommandBySelector:@selector(moveRight:)];
break;
case CPUpArrowKeyCode: [self doCommandBySelector:@selector(moveUp:)];
break;
case CPDownArrowKeyCode: [self doCommandBySelector:@selector(moveDown:)];
break;
case CPDeleteKeyCode: [self doCommandBySelector:@selector(deleteBackward:)];
break;
case CPReturnKeyCode:
case 3: [self doCommandBySelector:@selector(insertLineBreak:)];
break;
case CPEscapeKeyCode: [self doCommandBySelector:@selector(cancel:)];
break;
for (var s = 0, scount = selectorNames.length; s < scount; s++)
{
var selector = selectorNames[s];
if (!selector)
continue;
case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask;
if (!shift)
[self doCommandBySelector:@selector(insertTab:)];
else
[self doCommandBySelector:@selector(insertBackTab:)];
break;
default: [self insertText:[event characters]];
[self doCommandBySelector:CPSelectorFromString(selector)];
}
}
else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)) && [self respondsToSelector:@selector(insertText:)])
[self insertText:[event characters]];
}
}
@@ -152,6 +135,15 @@ CPDownArrowKeyCode = 40;
[_nextResponder performSelector:_cmd withObject:anEvent];
}
/*!
Notifies the receiver that the user has clicked the right mouse down in its area.
@param anEvent contains information about the right click
*/
- (void)rightMouseDown:(CPEvent)anEvent
{
[_nextResponder performSelector:_cmd withObject:anEvent];
}
/*!
Notifies the receiver that the user has initiated a drag
over it. A drag is a mouse movement while the left button is down.
@@ -171,6 +163,15 @@ CPDownArrowKeyCode = 40;
[_nextResponder performSelector:_cmd withObject:anEvent];
}
/*!
Notifies the receiver that the user has released the right mouse button.
@param anEvent contains information about the release
*/
- (void)rightMouseUp:(CPEvent)anEvent
{
[_nextResponder performSelector:_cmd withObject:anEvent];
}
/*!
Notifies the receiver that the user has moved the mouse (with no buttons down).
@param anEvent contains information about the movement
@@ -221,6 +222,15 @@ CPDownArrowKeyCode = 40;
[_nextResponder performSelector:_cmd withObject:anEvent];
}
/*!
Notifies the receiver that the user has pressed or released a modifier key (Shift, Control, and so on).
@param anEvent information about the key press
*/
- (void)flagsChanged:(CPEvent)anEvent
{
[_nextResponder performSelector:_cmd withObject:anEvent];
}
/*
FIXME This description is bad.
Based on \c anEvent, the receiver should simulate the event.
@@ -251,10 +261,6 @@ CPDownArrowKeyCode = 40;
[[self nextResponder] insertNewline:aSender];
}
- (void)cancel:(id)sender
{
}
- (void)insertTab:(id)sender
{
}
@@ -294,10 +300,10 @@ CPDownArrowKeyCode = 40;
*/
- (BOOL)tryToPerform:(SEL)aSelector with:(id)anObject
{
if([self respondsToSelector:aSelector])
if ([self respondsToSelector:aSelector])
{
[self performSelector:aSelector withObject:anObject];
return YES;
}
@@ -336,7 +342,8 @@ CPDownArrowKeyCode = 40;
@end
var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
CPResponderMenuKey = @"CPResponderMenuKey";
@implementation CPResponder (CPCoding)
@@ -348,10 +355,13 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey];
_menu = [aCoder decodeObjectForKey:CPResponderMenuKey];
}
return self;
}
@@ -364,6 +374,8 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
// This will come out nil on the other side with decodeObjectForKey:
if (_nextResponder !== nil)
[aCoder encodeConditionalObject:_nextResponder forKey:CPResponderNextResponderKey];
[aCoder encodeObject:_menu forKey:CPResponderMenuKey];
}
@end
+1 -1
View File
@@ -1,5 +1,5 @@
@import <AppKit/CPPanel.j>
@import "CPPanel.j"
@implementation CPSavePanel : CPPanel
+4 -2
View File
@@ -2,15 +2,17 @@
@import <Foundation/CPObject.j>
#import "CoreGraphics/CGGeometry.h"
@implementation CPScreen : CPObject
{
}
- (CGRect)visibleFrame
{
#if PLATFORM(DOM)
return _CGRectMake(window.screen.availLeft, window.screen.availTop, window.screen.availWidth, window.screen.availHeight);
#else
return _CGRectMakeZero();
#endif
}
@end
+386 -96
View File
@@ -20,14 +20,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPView.j"
@import "CPBox.j"
@import "CPClipView.j"
@import "CPScroller.j"
#include "CoreGraphics/CGGeometry.h"
@import "CPView.j"
/*!
/*!
@ingroup appkit
@class CPScrollView
@@ -37,23 +36,39 @@
*/
@implementation CPScrollView : CPView
{
CPClipView _contentView;
CPClipView _headerClipView;
CPView _cornerView;
CPClipView _contentView;
CPClipView _headerClipView;
CPView _cornerView;
CPView _bottomCornerView;
BOOL _hasVerticalScroller;
BOOL _hasHorizontalScroller;
BOOL _autohidesScrollers;
CPScroller _verticalScroller;
CPScroller _horizontalScroller;
int _recursionCount;
float _verticalLineScroll;
float _verticalPageScroll;
float _horizontalLineScroll;
float _horizontalPageScroll;
BOOL _hasVerticalScroller;
BOOL _hasHorizontalScroller;
BOOL _autohidesScrollers;
CPScroller _verticalScroller;
CPScroller _horizontalScroller;
int _recursionCount;
float _verticalLineScroll;
float _verticalPageScroll;
float _horizontalLineScroll;
float _horizontalPageScroll;
CPBorderType _borderType;
}
+ (CPString)defaultThemeClass
{
return @"scrollview"
}
+ (CPDictionary)themeAttributes
{
return [CPDictionary dictionaryWithJSObject:{
@"bottom-corner-color": [CPColor whiteColor],
@"border-color": [CPColor blackColor]
}];
}
- (id)initWithFrame:(CGRect)aFrame
@@ -68,14 +83,18 @@
_horizontalLineScroll = 10.0;
_horizontalPageScroll = 10.0;
_contentView = [[CPClipView alloc] initWithFrame:[self bounds]];
_borderType = CPNoBorder;
_contentView = [[CPClipView alloc] initWithFrame:[self _insetBounds]];
[self addSubview:_contentView];
_headerClipView = [[CPClipView alloc] init];
[self addSubview:_headerClipView];
_bottomCornerView = [[CPView alloc] init];
[self addSubview:_bottomCornerView];
[self setHasVerticalScroller:YES];
[self setHasHorizontalScroller:YES];
}
@@ -83,11 +102,70 @@
return self;
}
// Calculating Layout
+ (CGSize)contentSizeForFrameSize:(CGSize)frameSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
{
var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, frameSize.width, frameSize.height) borderType:borderType],
scrollerWidth = [CPScroller scrollerWidth];
if (hFlag)
bounds.size.height -= scrollerWidth;
if (vFlag)
bounds.size.width -= scrollerWidth;
return bounds.size;
}
+ (CGSize)frameSizeForContentSize:(CGSize)contentSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
{
var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, contentSize.width, contentSize.height) borderType:borderType],
widthInset = contentSize.width - bounds.size.width,
heightInset = contentSize.height - bounds.size.height,
frameSize = _CGSizeMake(contentSize.width + widthInset, contentSize.height + heightInset),
scrollerWidth = [CPScroller scrollerWidth];
if (hFlag)
frameSize.height -= scrollerWidth;
if (vFlag)
frameSize.width -= scrollerWidth;
return frameSize;
}
+ (CGRect)_insetBounds:(CGRect)bounds borderType:(CPBorderType)borderType
{
switch (borderType)
{
case CPLineBorder:
case CPBezelBorder:
return _CGRectInset(bounds, 1.0, 1.0);
case CPGrooveBorder:
bounds = _CGRectInset(bounds, 2.0, 2.0);
++bounds.origin.y;
--bounds.size.height;
return bounds;
case CPNoBorder:
default:
return bounds;
}
}
- (CGRect)_insetBounds
{
return [[self class] _insetBounds:[self bounds] borderType:_borderType];
}
// Determining component sizes
/*!
Returns the size of the scroll view's content view.
*/
- (CGRect)contentSize
- (CGSize)contentSize
{
return [_contentView frame].size;
}
@@ -106,7 +184,7 @@
*/
- (void)setContentView:(CPClipView)aContentView
{
if (_contentView !== aContentView || !aContentView)
if (_contentView === aContentView || !aContentView)
return;
var documentView = [aContentView documentView];
@@ -153,16 +231,16 @@
*/
- (void)reflectScrolledClipView:(CPClipView)aClipView
{
if(_contentView !== aClipView)
if (_contentView !== aClipView)
return;
if (_recursionCount > 5)
return;
++_recursionCount;
var documentView = [self documentView];
if (!documentView)
{
if (_autohidesScrollers)
@@ -176,7 +254,7 @@
// [_horizontalScroller setEnabled:NO];
}
[_contentView setFrame:[self bounds]];
[_contentView setFrame:[self _insetBounds]];
[_headerClipView setFrame:_CGRectMakeZero()];
--_recursionCount;
@@ -185,7 +263,7 @@
}
var documentFrame = [documentView frame], // the size of the whole document
contentFrame = [self bounds], // assume it takes up the entire size of the scrollview (no scrollers)
contentFrame = [self _insetBounds], // assume it takes up the entire size of the scrollview (no scrollers)
headerClipViewFrame = [self _headerClipViewFrame],
headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame);
@@ -235,11 +313,10 @@
if (shouldShowVerticalScroller)
{
var verticalScrollerY = MAX(_CGRectGetHeight([self _cornerViewFrame]), headerClipViewHeight),
verticalScrollerHeight = _CGRectGetHeight([self bounds]) - verticalScrollerY;
var verticalScrollerY =
MAX(_CGRectGetMinY(contentFrame), MAX(_CGRectGetMaxY([self _cornerViewFrame]), _CGRectGetMaxY(headerClipViewFrame)));
if (shouldShowHorizontalScroller)
verticalScrollerHeight -= horizontalScrollerHeight;
var verticalScrollerHeight = _CGRectGetMaxY(contentFrame) - verticalScrollerY;
[_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
[_verticalScroller setKnobProportion:_CGRectGetHeight(contentFrame) / _CGRectGetHeight(documentFrame)];
@@ -250,12 +327,12 @@
[_verticalScroller setFloatValue:0.0];
[_verticalScroller setKnobProportion:1.0];
}
if (shouldShowHorizontalScroller)
{
[_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
[_horizontalScroller setKnobProportion:_CGRectGetWidth(contentFrame) / _CGRectGetWidth(documentFrame)];
[_horizontalScroller setFrame:_CGRectMake(0.0, _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)];
[_horizontalScroller setFrame:_CGRectMake(_CGRectGetMinX(contentFrame), _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)];
}
else if (wasShowingHorizontalScroller)
{
@@ -267,9 +344,36 @@
[_headerClipView setFrame:headerClipViewFrame];
[_cornerView setFrame:[self _cornerViewFrame]];
[[self bottomCornerView] setFrame:[self _bottomCornerViewFrame]];
[[self bottomCornerView] setBackgroundColor:[self currentValueForThemeAttribute:@"bottom-corner-color"]];
--_recursionCount;
}
// Managing Graphics Attributes
/*!
Sets the type of border to be drawn around the view.
*/
- (void)setBorderType:(CPBorderType)borderType
{
if (_borderType == borderType)
return;
_borderType = borderType;
[self reflectScrolledClipView:_contentView];
[self setNeedsDisplay:YES];
}
/*!
Returns the border type drawn around the view.
*/
- (CPBorderType)borderType
{
return _borderType;
}
// Managing Scrollers
/*!
Sets the scroll view's horizontal scroller.
@@ -279,13 +383,13 @@
{
if (_horizontalScroller === aScroller)
return;
[_horizontalScroller removeFromSuperview];
[_horizontalScroller setTarget:nil];
[_horizontalScroller setAction:nil];
_horizontalScroller = aScroller;
[_horizontalScroller setTarget:self];
[_horizontalScroller setAction:@selector(_horizontalScrollerDidScroll:)];
@@ -316,8 +420,10 @@
if (_hasHorizontalScroller && !_horizontalScroller)
{
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth]+1), [CPScroller scrollerWidth])]];
[[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth])];
var bounds = [self _insetBounds];
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth(bounds), [CPScroller scrollerWidth] + 1), [CPScroller scrollerWidth])]];
[[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth(bounds), [CPScroller scrollerWidth])];
}
[self reflectScrolledClipView:_contentView];
@@ -339,13 +445,13 @@
{
if (_verticalScroller === aScroller)
return;
[_verticalScroller removeFromSuperview];
[_verticalScroller setTarget:nil];
[_verticalScroller setAction:nil];
_verticalScroller = aScroller;
[_verticalScroller setTarget:self];
[_verticalScroller setAction:@selector(_verticalScrollerDidScroll:)];
@@ -377,8 +483,10 @@
if (_hasVerticalScroller && !_verticalScroller)
{
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight([self bounds]), [CPScroller scrollerWidth]+1))]];
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight([self bounds]))];
var bounds = [self _insetBounds];
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight(bounds), [CPScroller scrollerWidth] + 1))]];
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight(bounds))];
}
[self reflectScrolledClipView:_contentView];
@@ -403,7 +511,7 @@
return;
_autohidesScrollers = autohidesScrollers;
[self reflectScrolledClipView:_contentView];
}
@@ -445,9 +553,7 @@
- (CPView)_headerView
{
var headerClipViewSubviews = [_headerClipView subviews];
return [headerClipViewSubviews count] ? headerClipViewSubviews[0] : nil;
return [_headerClipView documentView];
}
- (CGRect)_cornerViewFrame
@@ -455,11 +561,11 @@
if (!_cornerView)
return _CGRectMakeZero();
var bounds = [self bounds],
var bounds = [self _insetBounds],
frame = [_cornerView frame];
frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame);
frame.origin.y = 0;
frame.origin.y = _CGRectGetMinY(bounds);
return frame;
}
@@ -471,7 +577,7 @@
if (!headerView)
return _CGRectMakeZero();
var frame = [self bounds];
var frame = [self _insetBounds];
frame.size.height = _CGRectGetHeight([headerView frame]);
frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]);
@@ -479,33 +585,69 @@
return frame;
}
- (CGRect)_bottomCornerViewFrame
{
if ([[self horizontalScroller] isHidden] || [[self verticalScroller] isHidden])
return CGRectMakeZero();
var verticalFrame = [[self verticalScroller] frame],
bottomCornerFrame = CGRectMakeZero();
bottomCornerFrame.origin.x = CGRectGetMinX(verticalFrame);
bottomCornerFrame.origin.y = CGRectGetMaxY(verticalFrame);
bottomCornerFrame.size.width = [CPScroller scrollerWidth];
bottomCornerFrame.size.height = [CPScroller scrollerWidth];
return bottomCornerFrame;
}
- (void)setBottomCornerView:(CPView)aBottomCornerView
{
if (_bottomCornerView === aBottomCornerView)
return;
[_bottomCornerView removeFromSuperview];
[aBottomCornerView setFrame:[self _bottomCornerViewFrame]];
[self addSubview:aBottomCornerView];
_bottomCornerView = aBottomCornerView;
[self _updateCornerAndHeaderView];
}
- (CPView)bottomCornerView
{
return _bottomCornerView;
}
/* @ignore */
- (void)_verticalScrollerDidScroll:(CPScroller)aScroller
{
var value = [aScroller floatValue],
documentFrame = [[_contentView documentView] frame];
var value = [aScroller floatValue],
documentFrame = [[_contentView documentView] frame],
contentBounds = [_contentView bounds];
switch ([_verticalScroller hitPart])
{
case CPScrollerDecrementLine: contentBounds.origin.y -= _verticalLineScroll;
break;
case CPScrollerIncrementLine: contentBounds.origin.y += _verticalLineScroll;
break;
case CPScrollerDecrementPage: contentBounds.origin.y -= _CGRectGetHeight(contentBounds) - _verticalPageScroll;
break;
case CPScrollerIncrementPage: contentBounds.origin.y += _CGRectGetHeight(contentBounds) - _verticalPageScroll;
break;
case CPScrollerKnobSlot:
case CPScrollerKnob:
// We want integral bounds!
default: contentBounds.origin.y = ROUND(value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds)));
}
[_contentView scrollToPoint:contentBounds.origin];
}
@@ -515,21 +657,21 @@
var value = [aScroller floatValue],
documentFrame = [[self documentView] frame],
contentBounds = [_contentView bounds];
switch ([_horizontalScroller hitPart])
{
case CPScrollerDecrementLine: contentBounds.origin.x -= _horizontalLineScroll;
break;
case CPScrollerIncrementLine: contentBounds.origin.x += _horizontalLineScroll;
break;
case CPScrollerDecrementPage: contentBounds.origin.x -= _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
break;
case CPScrollerIncrementPage: contentBounds.origin.x += _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
break;
case CPScrollerKnobSlot:
case CPScrollerKnob:
// We want integral bounds!
@@ -554,7 +696,7 @@
/*
@ignore
*/
-(void)resizeSubviewsWithOldSize:(CGSize)aSize
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
{
[self reflectScrolledClipView:_contentView];
}
@@ -664,35 +806,169 @@
return _verticalPageScroll;
}
// CPView Overrides
- (void)drawRect:(CPRect)aRect
{
[super drawRect:aRect];
if (_borderType == CPNoBorder)
return;
var strokeRect = [self bounds],
context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSetLineWidth(context, 1);
switch (_borderType)
{
case CPLineBorder:
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"border-color"]);
CGContextStrokeRect(context, _CGRectInset(strokeRect, 0.5, 0.5));
break;
case CPBezelBorder:
[self _drawGrayBezelInContext:context bounds:strokeRect];
break;
case CPGrooveBorder:
[self _drawGrooveInContext:context bounds:strokeRect];
break;
default:
break;
}
}
- (void)_drawGrayBezelInContext:(CGContext)context bounds:(CGRect)aRect
{
CGContextBeginPath(context);
CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0 / 255.0 alpha:1.0]);
var y = _CGRectGetMinY(aRect) + 0.5;
CGContextMoveToPoint(context, _CGRectGetMinX(aRect), y);
CGContextAddLineToPoint(context, _CGRectGetMinX(aRect) + 1.0, y);
CGContextStrokePath(context);
CGContextBeginPath(context);
CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0 / 255.0 alpha:1.0]);
CGContextMoveToPoint(context, _CGRectGetMinX(aRect) + 1.0, y);
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y);
CGContextStrokePath(context);
CGContextBeginPath(context);
CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0 / 255.0 alpha:1.0]);
CGContextMoveToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y);
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect), y);
CGContextStrokePath(context);
CGContextBeginPath(context);
CGContextSetStrokeColor(context, [CPColor colorWithWhite:190.0 / 255.0 alpha:1.0]);
var x = _CGRectGetMaxX(aRect) - 0.5;
CGContextMoveToPoint(context, x, _CGRectGetMinY(aRect) + 1.0);
CGContextAddLineToPoint(context, x, _CGRectGetMaxY(aRect));
CGContextMoveToPoint(context, x - 0.5, _CGRectGetMaxY(aRect) - 0.5);
CGContextAddLineToPoint(context, _CGRectGetMinX(aRect), _CGRectGetMaxY(aRect) - 0.5);
x = _CGRectGetMinX(aRect) + 0.5;
CGContextMoveToPoint(context, x, _CGRectGetMaxY(aRect));
CGContextAddLineToPoint(context, x, _CGRectGetMinY(aRect) + 1.0);
CGContextStrokePath(context);
}
- (void)_drawGrooveInContext:(CGContext)context bounds:(CGRect)aRect
{
CGContextBeginPath(context);
CGContextSetStrokeColor(context, [CPColor colorWithWhite:159.0 / 255.0 alpha:1.0]);
var y = _CGRectGetMinY(aRect) + 0.5;
CGContextMoveToPoint(context, _CGRectGetMinX(aRect), y);
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect), y);
var x = _CGRectGetMaxX(aRect) - 1.5;
CGContextMoveToPoint(context, x, _CGRectGetMinY(aRect) + 2.0);
CGContextAddLineToPoint(context, x, _CGRectGetMaxY(aRect) - 1.0);
y = _CGRectGetMaxY(aRect) - 1.5;
CGContextMoveToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y);
CGContextAddLineToPoint(context, _CGRectGetMinX(aRect) + 2.0, y);
x = _CGRectGetMinX(aRect) + 0.5;
CGContextMoveToPoint(context, x, _CGRectGetMaxY(aRect));
CGContextAddLineToPoint(context, x, _CGRectGetMinY(aRect));
CGContextStrokePath(context);
CGContextBeginPath(context);
CGContextSetStrokeColor(context, [CPColor whiteColor]);
var rect = _CGRectOffset(aRect, 1.0, 1.0);
rect.size.width -= 1.0;
rect.size.height -= 1.0;
CGContextStrokeRect(context, _CGRectInset(rect, 0.5, 0.5));
CGContextBeginPath(context);
CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0 / 255.0 alpha:1.0]);
y = _CGRectGetMinY(aRect) + 2.5;
CGContextMoveToPoint(context, _CGRectGetMinX(aRect) + 2.0, y);
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect) - 2.0, y);
CGContextStrokePath(context);
}
// CPResponder Overrides
/*!
Handles a scroll wheel event from the user.
@param anEvent the scroll wheel event
*/
- (void)scrollWheel:(CPEvent)anEvent
{
var documentFrame = [[self documentView] frame],
contentBounds = [_contentView bounds];
[self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] deltaY:[anEvent deltaY]];
}
- (void)_respondToScrollWheelEventWithDeltaX:(float)deltaX deltaY:(float)deltaY
{
var documentFrame = [[self documentView] frame],
contentBounds = [_contentView bounds],
contentFrame = [_contentView frame],
enclosingScrollView = [self enclosingScrollView];
// We want integral bounds!
contentBounds.origin.x = ROUND(contentBounds.origin.x + [anEvent deltaX] * _horizontalLineScroll);
contentBounds.origin.y = ROUND(contentBounds.origin.y + [anEvent deltaY] * _verticalLineScroll);
contentBounds.origin.x = ROUND(contentBounds.origin.x + deltaX);
contentBounds.origin.y = ROUND(contentBounds.origin.y + deltaY);
[_contentView scrollToPoint:contentBounds.origin];
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)];
var constrainedOrigin = [_contentView constrainScrollPoint:CGPointCreateCopy(contentBounds.origin)],
extraX = contentBounds.origin.x - constrainedOrigin.x,
extraY = contentBounds.origin.y - constrainedOrigin.y;
[_contentView scrollToPoint:constrainedOrigin];
[_headerClipView scrollToPoint:CGPointMake(constrainedOrigin.x, 0.0)];
if (extraX || extraY)
[enclosingScrollView _respondToScrollWheelEventWithDeltaX:extraX deltaY:extraY];
}
- (void)keyDown:(CPEvent)anEvent
{
[self interpretKeyEvents:[anEvent]];
}
- (void)pageUp:(id)sender
- (void)scrollPageUp:(id)sender
{
var contentBounds = [_contentView bounds];
[self moveByOffset:CGSizeMake(0.0, -(_CGRectGetHeight(contentBounds) - _verticalPageScroll))];
}
- (void)pageDown:(id)sender
- (void)scrollPageDown:(id)sender
{
var contentBounds = [_contentView bounds];
[self moveByOffset:CGSizeMake(0.0, _CGRectGetHeight(contentBounds) - _verticalPageScroll)];
@@ -732,18 +1008,20 @@
@end
var CPScrollViewContentViewKey = "CPScrollViewContentView",
CPScrollViewHeaderClipViewKey = "CPScrollViewHeaderClipViewKey",
CPScrollViewVLineScrollKey = "CPScrollViewVLineScroll",
CPScrollViewHLineScrollKey = "CPScrollViewHLineScroll",
CPScrollViewVPageScrollKey = "CPScrollViewVPageScroll",
CPScrollViewHPageScrollKey = "CPScrollViewHPageScroll",
CPScrollViewHasVScrollerKey = "CPScrollViewHasVScroller",
CPScrollViewHasHScrollerKey = "CPScrollViewHasHScroller",
CPScrollViewVScrollerKey = "CPScrollViewVScroller",
CPScrollViewHScrollerKey = "CPScrollViewHScroller",
CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller",
CPScrollViewCornerViewKey = "CPScrollViewCornerViewKey";
var CPScrollViewContentViewKey = @"CPScrollViewContentView",
CPScrollViewHeaderClipViewKey = @"CPScrollViewHeaderClipViewKey",
CPScrollViewVLineScrollKey = @"CPScrollViewVLineScroll",
CPScrollViewHLineScrollKey = @"CPScrollViewHLineScroll",
CPScrollViewVPageScrollKey = @"CPScrollViewVPageScroll",
CPScrollViewHPageScrollKey = @"CPScrollViewHPageScroll",
CPScrollViewHasVScrollerKey = @"CPScrollViewHasVScroller",
CPScrollViewHasHScrollerKey = @"CPScrollViewHasHScroller",
CPScrollViewVScrollerKey = @"CPScrollViewVScroller",
CPScrollViewHScrollerKey = @"CPScrollViewHScroller",
CPScrollViewAutohidesScrollerKey = @"CPScrollViewAutohidesScroller",
CPScrollViewCornerViewKey = @"CPScrollViewCornerViewKey",
CPScrollViewBottomCornerViewKey = @"CPScrollViewBottomCornerViewKey",
CPScrollViewBorderTypeKey = @"CPScrollViewBorderTypeKey";
@implementation CPScrollView (CPCoding)
@@ -756,10 +1034,16 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
_horizontalLineScroll = [aCoder decodeFloatForKey:CPScrollViewHLineScrollKey];
_horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
_contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
_headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey];
if (!_headerClipView)
{
_headerClipView = [[CPClipView alloc] init];
[self addSubview:_headerClipView];
}
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
@@ -767,35 +1051,41 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
_hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
_autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
_borderType = [aCoder decodeIntForKey:CPScrollViewBorderTypeKey];
_cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
_bottomCornerView = [aCoder decodeObjectForKey:CPScrollViewBottomCornerViewKey];
// Do to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state.
[[CPRunLoop currentRunLoop] performSelector:@selector(reflectScrolledClipView:) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey];
[aCoder encodeObject:_headerClipView forKey:CPScrollViewHeaderClipViewKey];
[aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey];
[aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey];
[aCoder encodeFloat:_verticalLineScroll forKey:CPScrollViewVLineScrollKey];
[aCoder encodeFloat:_verticalPageScroll forKey:CPScrollViewVPageScrollKey];
[aCoder encodeFloat:_horizontalLineScroll forKey:CPScrollViewHLineScrollKey];
[aCoder encodeFloat:_horizontalPageScroll forKey:CPScrollViewHPageScrollKey];
[aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey];
[aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey];
[aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey];
[aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey];
[aCoder encodeObject:_bottomCornerView forKey:CPScrollViewBottomCornerViewKey];
[aCoder encodeInt:_borderType forKey:CPScrollViewBorderTypeKey];
}
@end
+95 -84
View File
@@ -22,8 +22,6 @@
@import "CPControl.j"
#include "CoreGraphics/CGGeometry.h"
// CPScroller Constants
CPScrollerNoPart = 0;
@@ -41,9 +39,9 @@ CPNoScrollerParts = 0;
CPOnlyScrollerArrows = 1;
CPAllScrollerParts = 2;
/*!
/*!
@ingroup appkit
@class CPScroller
@class CPScroller
*/
var PARTS_ARRANGEMENT = [CPScrollerKnobSlot, CPScrollerDecrementLine, CPScrollerIncrementLine, CPScrollerKnob],
@@ -72,24 +70,25 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
CGPoint _trackingStartPoint;
}
+ (CPString)themeClass
+ (CPString)defaultThemeClass
{
return "scroller";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[ [CPNull null], [CPNull null], [CPNull null], [CPNull null],
_CGSizeMakeZero(), _CGSizeMakeZero(), _CGInsetMakeZero(), _CGInsetMakeZero(), _CGSizeMakeZero()]
forKeys:[ @"knob-slot-color",
@"decrement-line-color",
@"increment-line-color",
@"knob-color",
@"decrement-line-size",
@"increment-line-size",
@"track-inset",
@"knob-inset",
@"minimum-knob-length"]];
return [CPDictionary dictionaryWithJSObject:{
@"scroller-width": 15.0,
@"knob-slot-color": [CPColor lightGrayColor],
@"decrement-line-color": [CPNull null],
@"increment-line-color": [CPNull null],
@"knob-color": [CPColor grayColor],
@"decrement-line-size":_CGSizeMakeZero(),
@"increment-line-size":_CGSizeMakeZero(),
@"track-inset":_CGInsetMakeZero(),
@"knob-inset": _CGInsetMakeZero(),
@"minimum-knob-length":21.0
}]
}
@@ -98,7 +97,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_controlSize = CPRegularControlSize;
@@ -106,7 +105,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
[self setFloatValue:0.0];
[self setKnobProportion:1.0];
_hitPart = CPScrollerNoPart;
[self _calculateIsVertical];
@@ -121,7 +120,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
*/
+ (float)scrollerWidth
{
return 15.0;//[self scrollerWidthForControlSize:CPRegularControlSize];
return [[[CPScroller alloc] init] currentValueForThemeAttribute:@"scroller-width"];
}
/*!
@@ -130,7 +129,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
*/
+ (float)scrollerWidthForControlSize:(CPControlSize)aControlSize
{
return 15.0;//_CPScrollerWidths[aControlSize];
return [self scrollerWidth];
}
/*!
@@ -180,10 +179,10 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (id)currentValueForThemeAttribute:(CPString)anAttributeName
{
var themeState = _themeState;
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
themeState &= ~CPThemeStateHighlighted;
return [self valueForThemeAttribute:anAttributeName inState:themeState];
}
@@ -205,25 +204,25 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (CPScrollerPart)testPart:(CGPoint)aPoint
{
aPoint = [self convertPoint:aPoint fromView:nil];
// The ordering of these tests is important. We check the knob and
// The ordering of these tests is important. We check the knob and
// page rects first since they may overlap with the arrows.
if (CGRectContainsPoint([self rectForPart:CPScrollerKnob], aPoint))
return CPScrollerKnob;
if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementPage], aPoint))
return CPScrollerDecrementPage;
if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementPage], aPoint))
return CPScrollerIncrementPage;
if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementLine], aPoint))
return CPScrollerDecrementLine;
if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementLine], aPoint))
return CPScrollerIncrementLine;
if (CGRectContainsPoint([self rectForPart:CPScrollerKnobSlot], aPoint))
return CPScrollerKnobSlot;
@@ -235,13 +234,13 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
*/
- (void)checkSpaceForParts
{
var bounds = [self bounds];
var bounds = [self bounds];
// Assume we won't be needing the arrows.
if (_knobProportion === 1.0)
{
_usableParts = CPNoScrollerParts;
_partRects[CPScrollerDecrementPage] = CGRectMakeZero();
_partRects[CPScrollerKnob] = CGRectMakeZero();
_partRects[CPScrollerIncrementPage] = CGRectMakeZero();
@@ -250,7 +249,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
// In this case, the slot is the entirety of the scroller.
_partRects[CPScrollerKnobSlot] = CGRectMakeCopy(bounds);
return;
}
@@ -260,8 +259,8 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
var knobInset = [self currentValueForThemeAttribute:@"knob-inset"],
trackInset = [self currentValueForThemeAttribute:@"track-inset"],
width = _CGRectGetWidth(bounds),
height = _CGRectGetHeight(bounds);
height = _CGRectGetHeight(bounds);
if ([self isVertical])
{
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
@@ -280,24 +279,23 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotHeight);
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
if(height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
if (height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
_partRects[CPScrollerKnob] = _CGRectMakeZero();
if(height < decrementLineSize.height + incrementLineSize.height - 2)
if (height < decrementLineSize.height + incrementLineSize.height - 2)
{
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, 0, width - trackInset.left - trackInset.right, height);
}
}
}
else
{
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"],
effectiveDecrementLineWidth = decrementLineSize.width + trackInset.left,
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right;
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right,
slotWidth = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
knobWidth = MAX(minimumKnobLength, (slotWidth * _knobProportion)),
@@ -310,11 +308,11 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotWidth, height - trackInset.top - trackInset.bottom);
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
if(width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
if (width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
_partRects[CPScrollerKnob] = _CGRectMakeZero();
if(width < decrementLineSize.width + incrementLineSize.width - 2)
if (width < decrementLineSize.width + incrementLineSize.width - 2)
{
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
@@ -359,9 +357,9 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (CPView)createViewForPart:(CPScrollerPart)aPart
{
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO];
return view;
}
@@ -375,7 +373,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO];
return view;
}
@@ -389,12 +387,12 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
for (; index < count; ++index)
{
var part = PARTS_ARRANGEMENT[index];
if (index === 0)
view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowBelow relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index + 1]];
else
view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowAbove relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index - 1]];
if (view)
[view setBackgroundColor:[self currentValueForThemeAttribute:NAMES_FOR_PARTS[part] + "-color"]];
}
@@ -404,7 +402,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
Caches images for the scroll arrow and knob.
*/
- (void)drawParts
{
{
[self drawKnobSlot];
[self drawKnob];
[self drawArrow:CPScrollerDecrementArrow highlight:NO];
@@ -427,37 +425,37 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (void)trackKnob:(CPEvent)anEvent
{
var type = [anEvent type];
if (type === CPLeftMouseUp)
{
_hitPart = CPScrollerNoPart;
return;
}
if (type === CPLeftMouseDown)
{
_trackingFloatValue = [self floatValue];
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
}
else if (type === CPLeftMouseDragged)
{
var knobRect = [self rectForPart:CPScrollerKnob],
knobSlotRect = [self rectForPart:CPScrollerKnobSlot],
remainder = ![self isVertical] ? (_CGRectGetWidth(knobSlotRect) - _CGRectGetWidth(knobRect)) : (_CGRectGetHeight(knobSlotRect) - _CGRectGetHeight(knobRect));
if (remainder <= 0)
[self setFloatValue:0.0];
else
{
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
delta = ![self isVertical] ? location.x - _trackingStartPoint.x : location.y - _trackingStartPoint.y;
[self setFloatValue:_trackingFloatValue + delta / remainder];
}
}
[CPApp setTarget:self selector:@selector(trackKnob:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
[self sendAction:[self action] to:[self target]];
@@ -475,26 +473,26 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
{
[self highlight:NO];
[CPEvent stopPeriodicEvents];
_hitPart = CPScrollerNoPart;
return;
}
if (type === CPLeftMouseDown)
{
_trackingPart = [self hitPart];
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if ([anEvent modifierFlags] & CPAlternateKeyMask)
{
if (_trackingPart == CPScrollerDecrementLine)
_hitPart = CPScrollerDecrementPage;
else if (_trackingPart == CPScrollerIncrementLine)
_hitPart = CPScrollerIncrementPage;
else if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
{
var knobRect = [self rectForPart:CPScrollerKnob],
@@ -503,42 +501,42 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
remainder = (![self isVertical] ? _CGRectGetWidth(knobSlotRect) : _CGRectGetHeight(knobSlotRect)) - knobWidth;
[self setFloatValue:((![self isVertical] ? _trackingStartPoint.x - _CGRectGetMinX(knobSlotRect) : _trackingStartPoint.y - _CGRectGetMinY(knobSlotRect)) - knobWidth / 2.0) / remainder];
_hitPart = CPScrollerKnob;
[self sendAction:[self action] to:[self target]];
[self sendAction:[self action] to:[self target]];
// Now just track the knob.
return [self trackKnob:anEvent];
}
}
[self highlight:YES];
[self sendAction:[self action] to:[self target]];
[CPEvent startPeriodicEventsAfterDelay:0.5 withPeriod:0.04];
}
else if (type === CPLeftMouseDragged)
{
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
{
var hitPart = [self testPart:[anEvent locationInWindow]];
if (hitPart == CPScrollerDecrementPage || hitPart == CPScrollerIncrementPage)
{
_trackingPart = hitPart;
_hitPart = hitPart;
}
}
[self highlight:CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint)];
}
else if (type == CPPeriodic && CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint))
[self sendAction:[self action] to:[self target]];
[CPApp setTarget:self selector:@selector(trackScrollButtons:) forNextEventMatchingMask:CPPeriodicMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
@@ -570,15 +568,15 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
{
if (![self isEnabled])
return;
_hitPart = [self testPart:[anEvent locationInWindow]];
switch (_hitPart)
{
case CPScrollerKnob: return [self trackKnob:anEvent];
case CPScrollerDecrementLine:
case CPScrollerIncrementLine:
case CPScrollerDecrementLine:
case CPScrollerIncrementLine:
case CPScrollerDecrementPage:
case CPScrollerIncrementPage: return [self trackScrollButtons:anEvent];
}
@@ -604,19 +602,32 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
_knobProportion = [aCoder decodeFloatForKey:CPScrollerKnobProportionKey];
_partRects = [];
_hitPart = CPScrollerNoPart;
[self _calculateIsVertical];
// Adjust the size of the scroller if the size from cib
// isn't equal to the scrollerWidth
var frame = [self frame],
scrollerWidth = [CPScroller scrollerWidth];
if ([self isVertical] && CGRectGetWidth(frame) !== scrollerWidth)
frame.size.width = scrollerWidth;
if (![self isVertical] && CGRectGetHeight(frame) !== scrollerWidth)
frame.size.height = scrollerWidth;
[self setFrame:frame];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeInt:_controlSize forKey:CPScrollerControlSizeKey];
[aCoder encodeFloat:_knobProportion forKey:CPScrollerKnobProportionKey];
}
+233 -130
View File
@@ -20,20 +20,28 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPButton.j"
@import "CPTextField.j"
#include "Platform/Platform.h"
CPSearchFieldRecentsTitleMenuItemTag = 1000;
CPSearchFieldRecentsMenuItemTag = 1001;
CPSearchFieldClearRecentsMenuItemTag = 1002;
CPSearchFieldNoRecentsMenuItemTag = 1003;
CPSearchFieldSeparatorMenuItemTag = 1004;
var CPSearchFieldSearchImage = nil,
CPSearchFieldFindImage = nil,
CPSearchFieldCancelImage = nil,
CPSearchFieldCancelPressedImage = nil;
var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0,
CANCEL_BUTTON_DEFAULT_WIDTH = 22.0,
BUTTON_DEFAULT_HEIGHT = 22.0;
var RECENT_SEARCH_PREFIX = @" ";
/*!
@ingroup appkit
@class CPSearchField
@@ -54,32 +62,37 @@ var CPSearchFieldSearchImage = nil,
int _maximumRecents;
BOOL _sendsWholeSearchString;
BOOL _sendsSearchStringImmediately;
BOOL _canResignFirstResponder;
CPTimer _partialStringTimer;
}
+ (CPString)defaultThemeClass
{
return @"searchfield"
}
+ (void)initialize
{
if (self != [CPSearchField class])
return;
var bundle = [CPBundle bundleForClass:self];
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:CGSizeMake(25, 22)];
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:CGSizeMake(25, 22)];
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:CGSizeMake(22, 22)];
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:CGSizeMake(22, 22)];
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
}
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
_recentSearches = [CPArray array];
_maximumRecents = 10;
_sendsWholeSearchString = NO;
_sendsSearchStringImmediately = NO;
_recentsAutosaveName = nil;
[self _initWithFrame:frame];
[self _init];
#if PLATFORM(DOM)
_cancelButton._DOMElement.style.cursor = "default";
_searchButton._DOMElement.style.cursor = "default";
@@ -89,23 +102,28 @@ var CPSearchFieldSearchImage = nil,
return self;
}
- (void)_initWithFrame:(CGRect)frame
- (void)_init
{
_recentSearches = [CPArray array];
[self setBezeled:YES];
[self setBezelStyle:CPTextFieldRoundedBezel];
[self setBordered:YES];
[self setEditable:YES];
[self setDelegate:self];
[self setContinuous:YES];
_cancelButton = [[CPButton alloc] initWithFrame:CGRectMake(frame.size.width - 27,(frame.size.height-22)/2,22,22)];
var bounds = [self bounds],
cancelButton = [[CPButton alloc] initWithFrame:[self cancelButtonRectForBounds:bounds]],
searchButton = [[CPButton alloc] initWithFrame:[self searchButtonRectForBounds:bounds]];
[self setCancelButton:cancelButton];
[self resetCancelButton];
[_cancelButton setHidden:YES];
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
[self addSubview:_cancelButton];
_searchButton = [[CPButton alloc] initWithFrame:CGRectMake(5,(frame.size.height-25)/2,25,25)];
[self setSearchButton:searchButton];
[self resetSearchButton];
[self addSubview:_searchButton];
_canResignFirstResponder = YES;
}
// Managing Buttons
@@ -115,7 +133,15 @@ var CPSearchFieldSearchImage = nil,
*/
- (void)setSearchButton:(CPButton)button
{
_searchButton = button;
if (button != _searchButton)
{
[_searchButton removeFromSuperview];
_searchButton = button;
[_searchButton setFrame:[self searchButtonRectForBounds:[self bounds]]];
[_searchButton setAutoresizingMask:CPViewMaxXMargin];
[self addSubview:_searchButton];
}
}
/*!
@@ -133,30 +159,13 @@ var CPSearchFieldSearchImage = nil,
*/
- (void)resetSearchButton
{
var searchButtonImage,
action,
target,
button = [self searchButton];
if (_searchMenuTemplate === nil)
{
searchButtonImage = CPSearchFieldSearchImage;
action = @selector(_sendAction:);
target = self;
}
else
{
searchButtonImage = CPSearchFieldFindImage;
action = @selector(_showMenu:);
target = self;
}
var button = [self searchButton],
searchButtonImage = (_searchMenuTemplate === nil) ? CPSearchFieldSearchImage : CPSearchFieldFindImage;
[button setBordered:NO];
[button setImageScaling:CPScaleToFit];
[button setImage:searchButtonImage];
[button setAutoresizingMask:CPViewMaxXMargin];
[button setTarget:target];
[button setAction:action];
}
/*!
@@ -165,7 +174,18 @@ var CPSearchFieldSearchImage = nil,
*/
- (void)setCancelButton:(CPButton)button
{
_cancelButton = button;
if (button != _cancelButton)
{
[_cancelButton removeFromSuperview];
_cancelButton = button;
[_cancelButton setFrame:[self cancelButtonRectForBounds:[self bounds]]];
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
[_cancelButton setTarget:self];
[_cancelButton setAction:@selector(_searchFieldCancel:)];
[self _updateCancelButtonVisibility];
[self addSubview:_cancelButton];
}
}
/*!
@@ -200,23 +220,25 @@ var CPSearchFieldSearchImage = nil,
@return The updated bounding rectangle to use for the search text field. The default value is the value passed into the rect parameter.
Subclasses can override this method to return a new bounding rectangle for the text-field object. You might use this method to provide a custom layout for the search field control.
*/
- (CPRect)searchTextRectForBounds:(CPRect)rect
- (CGRect)searchTextRectForBounds:(CGRect)rect
{
var leftOffset = 0, width = rect.size.width;
var leftOffset = 0,
width = _CGRectGetWidth(rect),
bounds = [self bounds];
if (_searchButton)
{
var searchRect = [_searchButton frame];
leftOffset = searchRect.origin.x + searchRect.size.width;
var searchBounds = [self searchButtonRectForBounds:bounds];
leftOffset = _CGRectGetMaxX(searchBounds) + 2;
}
if (_cancelButton)
{
var cancelRect = [_cancelButton frame];
width = cancelRect.origin.x - leftOffset;
var cancelRect = [self cancelButtonRectForBounds:bounds];
width = _CGRectGetMinX(cancelRect) - leftOffset;
}
return CPMakeRect(leftOffset,rect.origin.y,width,rect.size.height);
return _CGRectMake(leftOffset, _CGRectGetMinY(rect), width, _CGRectGetHeight(rect));
}
/*!
@@ -224,9 +246,9 @@ var CPSearchFieldSearchImage = nil,
@param rect The current bounding rectangle for the search button.
Subclasses can override this method to return a new bounding rectangle for the search button. You might use this method to provide a custom layout for the search field control.
*/
- (CPRect)searchButtonRectForBounds:(CPRect)rect
- (CGRect)searchButtonRectForBounds:(CGRect)rect
{
return [_searchButton frame];
return _CGRectMake(5, (_CGRectGetHeight(rect) - BUTTON_DEFAULT_HEIGHT) / 2, SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT);
}
/*!
@@ -234,9 +256,9 @@ var CPSearchFieldSearchImage = nil,
@param rect The updated bounding rectangle to use for the cancel button. The default value is the value passed into the rect parameter.
Subclasses can override this method to return a new bounding rectangle for the cancel button. You might use this method to provide a custom layout for the search field control.
*/
- (CPRect)cancelButtonRectForBounds:(CPRect)rect
{
return [_cancelButton frame];
- (CGRect)cancelButtonRectForBounds:(CGRect)rect
{
return _CGRectMake(_CGRectGetWidth(rect) - CANCEL_BUTTON_DEFAULT_WIDTH - 5, (_CGRectGetHeight(rect) - CANCEL_BUTTON_DEFAULT_WIDTH) / 2, BUTTON_DEFAULT_HEIGHT, BUTTON_DEFAULT_HEIGHT);
}
// Managing Menu Templates
@@ -254,9 +276,9 @@ var CPSearchFieldSearchImage = nil,
@param menu The menu template to use.
The receiver looks for the tag constants described in ŇMenu tagsÓ to determine how to populate the menu with items related to recent searches. See ŇConfiguring a Search MenuÓ for a sample of how you might set up the search menu template.
*/
- (void)setSearchMenuTemplate:(CPMenu)menu
- (void)setSearchMenuTemplate:(CPMenu)aMenu
{
_searchMenuTemplate = menu;
_searchMenuTemplate = aMenu;
[self resetSearchButton];
[self _loadRecentSearchList];
@@ -373,7 +395,7 @@ var CPSearchFieldSearchImage = nil,
// Private methods and subclassing
- (CPRect)contentRectForBounds:(CPRect)bounds
- (CGRect)contentRectForBounds:(CGRect)bounds
{
var superbounds = [super contentRectForBounds:bounds];
return [self searchTextRectForBounds:superbounds];
@@ -447,37 +469,78 @@ var CPSearchFieldSearchImage = nil,
[self _updateSearchMenu];
}
- (BOOL)trackMouse:(CPEvent)event
- (CPView)hitTest:(CGPoint)aPoint
{
var rect,
point,
location = [event locationInWindow];
point = [self convertPoint:location fromView:nil];
rect = [self searchButtonRectForBounds:[self frame]];
if (CPRectContainsPoint(rect,point))
{
return [[self searchButton] trackMouse:event];
}
rect = [self cancelButtonRectForBounds:[self frame]];
if (CPRectContainsPoint(rect,point))
{
return [[self cancelButton] trackMouse:event];
}
return [super trackMouse:event];
// Make sure a hit anywhere within the search field returns the search field itself
if (_CGRectContainsPoint([self frame], aPoint))
return self;
else
return nil;
}
- (CPMenu)_defaultSearchMenuTemplate
- (BOOL)resignFirstResponder
{
var template, item;
return _canResignFirstResponder && [super resignFirstResponder];
}
- (void)mouseDown:(CPEvent)anEvent
{
var location = [anEvent locationInWindow],
point = [self convertPoint:location fromView:nil];
if (_CGRectContainsPoint([self searchButtonRectForBounds:[self bounds]], point))
{
if (_searchMenuTemplate == nil)
[self _sendAction:self];
else
[self _showMenu];
}
else if (_CGRectContainsPoint([self cancelButtonRectForBounds:[self bounds]], point))
[_cancelButton mouseDown:anEvent];
else
[super mouseDown:anEvent];
}
/*!
Provides the common case items for a recent searches menu. If there are not recent searches,
displays a single disabled item:
template = [[CPMenu alloc] init];
No Recent Searches
If there are 1 more recent searches, it displays:
item = [[CPMenuItem alloc] initWithTitle:@"Recent searches"
action:NULL
Recent Searches
recent search 1
recent search 2
etc.
---------------------
Clear Recent Searches
If you wish to add items before or after the template, you can. If you put items
before, a separator will automatically be placed before the default template item.
If you add items after the default template, it is your responsibility to add a separator.
To add a custom item:
item = [[CPMenuItem alloc] initWithTitle:@"google"
action:@selector(google:)
keyEquivalent:@""];
[item setTag:700];
[item setTarget:self];
[template addItem:item];
Be sure that your custom items do not use tags in the range 1000-1004 inclusive.
If you wish to maintain state in custom menu items that you add, you will need to maintain
the item state yourself, then in the action method of the custom items, modify the items
in the search menu template and send [searchField setSearchMenuTemplate:template] to update the menu.
*/
- (CPMenu)defaultSearchMenuTemplate
{
var template = [[CPMenu alloc] init],
item;
item = [[CPMenuItem alloc] initWithTitle:@"Recent Searches"
action:nil
keyEquivalent:@""];
[item setTag:CPSearchFieldRecentsTitleMenuItemTag];
[item setEnabled:NO];
@@ -490,15 +553,15 @@ var CPSearchFieldSearchImage = nil,
[item setTarget:self];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"Clear recent searches"
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:NULL
item = [[CPMenuItem alloc] initWithTitle:@"No Recent Searches"
action:nil
keyEquivalent:@""];
[item setTag:CPSearchFieldNoRecentsMenuItemTag];
[item setEnabled:NO];
@@ -512,61 +575,96 @@ var CPSearchFieldSearchImage = nil,
if (_searchMenuTemplate === nil)
return;
var i, menu = [[CPMenu alloc] init],
var menu = [[CPMenu alloc] init],
countOfRecents = [_recentSearches count],
numberOfItems = [_searchMenuTemplate numberOfItems];
for (i = 0; i < numberOfItems; i++)
for (var i = 0; i < numberOfItems; i++)
{
var item = [_searchMenuTemplate itemAtIndex:i],
tag = [item tag];
if (!(tag === CPSearchFieldRecentsTitleMenuItemTag && countOfRecents === 0) &&
!(tag === CPSearchFieldClearRecentsMenuItemTag && countOfRecents === 0) &&
!(tag === CPSearchFieldNoRecentsMenuItemTag && countOfRecents != 0) &&
!(tag === CPSearchFieldRecentsMenuItemTag))
{
var itemAction, itemTarget;
switch (tag)
{
case CPSearchFieldRecentsTitleMenuItemTag : itemAction = NULL; itemTarget = NULL; break;
case CPSearchFieldClearRecentsMenuItemTag : itemAction = @selector(_searchFieldClearRecents:); itemTarget = self; break;
case CPSearchFieldNoRecentsMenuItemTag : itemAction = NULL; itemTarget = NULL; break;
default: itemAction = [item action]; itemTarget = [item target]; break;
}
var item = [[_searchMenuTemplate itemAtIndex:i] copy];
if (tag === CPSearchFieldClearRecentsMenuItemTag || tag === CPSearchFieldRecentsTitleMenuItemTag)
{
var separator = [CPMenuItem separatorItem];
[separator setEnabled:NO];
[menu addItem:separator];
}
var templateItem = [[CPMenuItem alloc] initWithTitle:[item title]
action:itemAction
keyEquivalent:[item keyEquivalent]];
[templateItem setTarget:itemTarget];
[templateItem setEnabled:([item isEnabled] && itemAction != NULL)];
[templateItem setTag:tag];
[menu addItem:templateItem];
}
else if (tag === CPSearchFieldRecentsMenuItemTag)
switch ([item tag])
{
var j;
for (j = 0; j < countOfRecents; j++)
case CPSearchFieldRecentsTitleMenuItemTag:
if (countOfRecents === 0)
continue;
if ([menu numberOfItems] > 0)
[self _addSeparatorToMenu:menu];
break;
case CPSearchFieldRecentsMenuItemTag:
{
var rencentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j]
action:@selector(_searchFieldSearch:)
keyEquivalent:[item keyEquivalent]];
[rencentItem setTarget:self];
[menu addItem:rencentItem];
var itemAction = @selector(_searchFieldSearch:);
for (var recentIndex = 0; recentIndex < countOfRecents; ++recentIndex)
{
// RECENT_SEARCH_PREFIX is a hack until CPMenuItem -setIndentationLevel works
var recentItem = [[CPMenuItem alloc] initWithTitle:RECENT_SEARCH_PREFIX + [_recentSearches objectAtIndex:recentIndex]
action:itemAction
keyEquivalent:[item keyEquivalent]];
[item setTarget:self];
[menu addItem:recentItem];
}
continue;
}
case CPSearchFieldClearRecentsMenuItemTag:
if (countOfRecents === 0)
continue;
if ([menu numberOfItems] > 0)
[self _addSeparatorToMenu:menu];
[item setAction:@selector(_searchFieldClearRecents:)];
[item setTarget:self];
break;
case CPSearchFieldNoRecentsMenuItemTag:
if (countOfRecents !== 0)
continue;
if ([menu numberOfItems] > 0)
[self _addSeparatorToMenu:menu];
break;
case CPSearchFieldSeparatorMenuItemTag:
item = [CPMenuItem separatorItem];
[item setEnabled:NO];
[menu addItem:item];
continue;
}
}
[item setEnabled:([item isEnabled] && [item action] != nil && [item target] != nil)];
[menu addItem:item];
}
[menu setDelegate:self];
_searchMenu = menu;
}
- (void)_showMenu:(id)sender
- (void)_addSeparatorToMenu:(CPMenu)aMenu
{
var separator = [CPMenuItem separatorItem];
[separator setEnabled:NO];
[aMenu addItem:separator];
}
- (void)menuWillOpen:(CPMenu)menu
{
_canResignFirstResponder = NO;
}
- (void)menuDidClose:(CPMenu)menu
{
_canResignFirstResponder = YES;
[self becomeFirstResponder];
}
- (void)_showMenu
{
if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled])
return;
@@ -576,12 +674,14 @@ var CPSearchFieldSearchImage = nil,
var anEvent = [CPEvent mouseEventWithType:CPRightMouseDown location:location modifierFlags:0 timestamp:[[CPApp currentEvent] timestamp] windowNumber:[[self window] windowNumber] context:nil eventNumber:1 clickCount:1 pressure:0];
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:sender];
[self selectAll:nil];
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:self];
}
- (void)_sendPartialString
{
[[self target] performSelector:[self action] withObject:self];
[super sendAction:[self action] to:[self target]];
[_partialStringTimer invalidate];
}
- (void)_searchFieldCancel:(id)sender
@@ -593,14 +693,15 @@ var CPSearchFieldSearchImage = nil,
- (void)_searchFieldSearch:(id)sender
{
var searchString = [sender title];
var searchString = [[sender title] substringFromIndex:[RECENT_SEARCH_PREFIX length]];
if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
[self _addStringToRecentSearches:searchString];
[self setObjectValue:searchString];
[self _sendPartialString];
[self selectAll:nil];
[self _updateCancelButtonVisibility];
}
@@ -608,6 +709,8 @@ var CPSearchFieldSearchImage = nil,
{
[self setRecentSearches:[CPArray array]];
[self _updateSearchMenu];
[self setStringValue:@""];
[self _updateCancelButtonVisibility];
}
- (void)_registerForAutosaveNotification
@@ -668,7 +771,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
CPMaximumRecentsKey = @"CPMaximumRecentsKey",
CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey";
CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey";
@implementation CPSearchField (CPCoding)
@@ -690,6 +793,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
if (_recentsAutosaveName)
[coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
if (_searchMenuTemplate)
[coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
}
@@ -698,18 +802,17 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
{
if (self = [super initWithCoder:coder])
{
[self _initWithFrame:[self frame]];
_recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey];
_sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
_sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
_maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey];
var template = [coder decodeObjectForKey:CPSearchMenuTemplateKey];
if (template)
[self setSearchMenuTemplate:template];
[self setDelegate:self];
[self _init];
}
return self;
+1
View File
@@ -1,6 +1,7 @@
@import "CPTextField.j"
/*!
@ingroup appkit
*/
+132 -133
View File
@@ -24,13 +24,12 @@
@import "CPControl.j"
#include "CoreGraphics/CGGeometry.h"
CPSegmentSwitchTrackingSelectOne = 0;
CPSegmentSwitchTrackingSelectAny = 1;
CPSegmentSwitchTrackingMomentary = 2;
/*!
/*!
@ingroup appkit
@class CPSegmentedControl
@@ -49,7 +48,7 @@ CPSegmentSwitchTrackingMomentary = 2;
BOOL _trackingHighlighted;
}
+ (CPString)themeClass
+ (CPString)defaultThemeClass
{
return "segmented-control";
}
@@ -64,16 +63,16 @@ CPSegmentSwitchTrackingMomentary = 2;
{
_segments = [];
_themeStates = [];
self = [super initWithFrame:aRect];
if (self)
{
_selectedSegment = -1;
_trackingMode = CPSegmentSwitchTrackingSelectOne;
}
return self;
}
@@ -82,7 +81,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (int)selectedTag
{
return _segments[_selectedSegment].tag;
return [_segments[_selectedSegment] tag];
}
// Specifying the number of segments
@@ -94,11 +93,11 @@ CPSegmentSwitchTrackingMomentary = 2;
{
if (_segments.length == aCount)
return;
var height = CGRectGetHeight([self bounds]);
if (_segments.length < aCount)
{
{
for (var index = _segments.length; index < aCount; ++index)
{
_segments[index] = [[_CPSegmentItem alloc] init];
@@ -151,15 +150,15 @@ CPSegmentSwitchTrackingMomentary = 2;
- (BOOL)selectSegmentWithTag:(int)aTag
{
var index = 0;
for (; index < _segments.length; ++index)
if (_segments[index].tag == aTag)
{
[self setSelectedSegment:index];
return YES;
}
return NO;
}
@@ -174,28 +173,28 @@ CPSegmentSwitchTrackingMomentary = 2;
{
if (_trackingMode == aTrackingMode)
return;
_trackingMode = aTrackingMode;
if (_trackingMode == CPSegmentSwitchTrackingSelectOne)
{
var index = 0,
selected = NO;
for (; index < _segments.length; ++index)
if (_segments[index].selected)
if ([_segments[index] selected])
if (selected)
[self setSelected:NO forSegment:index];
else
selected = YES;
}
else if (_trackingMode == CPSegmentSwitchTrackingMomentary)
{
var index = 0;
for (; index < _segments.length; ++index)
if (_segments[index].selected)
if ([_segments[index] selected])
[self setSelected:NO forSegment:index];
}
}
@@ -217,8 +216,8 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
{
_segments[aSegment].width = aWidth;
[_segments[aSegment] setWidth:aWidth];
[self tileWithChangedSegment:aSegment];
}
@@ -229,7 +228,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (float)widthForSegment:(unsigned)aSegment
{
return _segments[aSegment].width;
return [_segments[aSegment] width];
}
/*!
@@ -240,9 +239,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
{
var segment = _segments[aSegment];
segment.image = anImage;
[_segments[aSegment] setImage:anImage];
[self tileWithChangedSegment:aSegment];
}
@@ -254,7 +251,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (CPImage)imageForSegment:(unsigned)aSegment
{
return _segments[aSegment].image;
return [_segments[aSegment] image];
}
/*!
@@ -265,10 +262,8 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
{
var segment = _segments[aSegment];
_segments[aSegment].label = aLabel;
[_segments[aSegment] setLabel:aLabel];
[self tileWithChangedSegment:aSegment];
}
@@ -279,7 +274,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (CPString)labelForSegment:(unsigned)aSegment
{
return _segments[aSegment].label;
return [_segments[aSegment] label];
}
/*!
@@ -290,7 +285,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
{
_segments[aSegment].menu = aMenu;
[_segments[aSegment] setMenu:aMenu];
}
/*!
@@ -300,7 +295,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (CPMenu)menuForSegment:(unsigned)aSegment
{
return _segments[aSegment].menu;
return [_segments[aSegment] menu];
}
/*!
@@ -313,12 +308,12 @@ CPSegmentSwitchTrackingMomentary = 2;
- (void)setSelected:(BOOL)isSelected forSegment:(unsigned)aSegment
{
var segment = _segments[aSegment];
// If we're already in this state, bail.
if (segment.selected == isSelected)
if ([segment selected] == isSelected)
return;
segment.selected = isSelected;
[segment setSelected:isSelected];
_themeStates[aSegment] = isSelected ? CPThemeStateSelected : CPThemeStateNormal;
@@ -326,18 +321,18 @@ CPSegmentSwitchTrackingMomentary = 2;
if (isSelected)
{
var oldSelectedSegment = _selectedSegment;
_selectedSegment = aSegment;
if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1)
{
_segments[oldSelectedSegment].selected = NO;
[_segments[oldSelectedSegment] setSelected:NO];
_themeStates[oldSelectedSegment] = CPThemeStateNormal;
[self drawSegmentBezel:oldSelectedSegment highlight:NO];
}
}
if (_trackingMode != CPSegmentSwitchTrackingMomentary)
[self drawSegmentBezel:aSegment highlight:NO];
@@ -352,7 +347,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (BOOL)isSelectedForSegment:(unsigned)aSegment
{
return _segments[aSegment].selected;
return [_segments[aSegment] selected];
}
/*!
@@ -363,6 +358,8 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
{
[_segments[aSegment] setEnabled:isEnabled];
if (isEnabled)
_themeStates[aSegment] &= ~CPThemeStateDisabled;
else
@@ -379,7 +376,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (BOOL)isEnabledForSegment:(unsigned)aSegment
{
return !(_themeStates[aSegment] & CPThemeStateDisabled)
return [_segments[aSegment] enabled];
}
/*!
@@ -389,7 +386,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setTag:(int)aTag forSegment:(unsigned)aSegment
{
_segments[aSegment].tag = aTag;
[_segments[aSegment] setTag:aTag];
}
/*!
@@ -398,7 +395,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (int)tagForSegment:(unsigned)aSegment
{
return _segments[aSegment].tag;
return [_segments[aSegment] tag];
}
// Drawings
@@ -461,7 +458,7 @@ CPSegmentSwitchTrackingMomentary = 2;
else if (aName.indexOf("segment-bezel") === 0)
{
var segment = parseInt(aName.substring("segment-bezel-".length), 10),
frame = CGRectCreateCopy(_segments[segment].frame);
frame = CGRectCreateCopy([_segments[segment] frame]);
if (segment === 0)
{
@@ -495,7 +492,7 @@ CPSegmentSwitchTrackingMomentary = 2;
- (CPView)createEphemeralSubviewNamed:(CPString)aName
{
if (aName.substring(0, "segment-content".length) == "segment-content")
if ([aName hasPrefix:@"segment-content"])
return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
@@ -510,10 +507,10 @@ CPSegmentSwitchTrackingMomentary = 2;
themeState |= _themeState & CPThemeStateDisabled;
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
inState:themeState];
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
inState:themeState],
var leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil];
@@ -523,41 +520,39 @@ CPSegmentSwitchTrackingMomentary = 2;
themeState |= _themeState & CPThemeStateDisabled;
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
inState:themeState];
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
inState:themeState],
var rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil];
[rightBezelView setBackgroundColor:rightCapColor];
for (var i=0, count = _themeStates.length; i<count; i++)
for (var i = 0, count = _themeStates.length; i < count; i++)
{
var themeState = _themeStates[i];
themeState |= _themeState & CPThemeStateDisabled;
var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color"
inState:themeState];
var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color"
inState:themeState],
var bezelView = [self layoutEphemeralSubviewNamed:"segment-bezel-"+i
positioned:CPWindowBelow
bezelView = [self layoutEphemeralSubviewNamed:"segment-bezel-" + i
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil];
[bezelView setBackgroundColor:bezelColor];
//layout image/title views
var segment = _segments[i];
var contentView = [self layoutEphemeralSubviewNamed:@"segment-content-"+i
// layout image/title views
var segment = _segments[i],
contentView = [self layoutEphemeralSubviewNamed:@"segment-content-" + i
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"segment-bezel-"+i];
relativeToEphemeralSubviewNamed:@"segment-bezel-" + i];
[contentView setText:segment.label];
[contentView setImage:segment.image];
[contentView setText:[segment label]];
[contentView setImage:[segment image]];
[contentView setFont:[self valueForThemeAttribute:@"font" inState:themeState]];
[contentView setTextColor:[self valueForThemeAttribute:@"text-color" inState:themeState]];
@@ -566,27 +561,27 @@ CPSegmentSwitchTrackingMomentary = 2;
[contentView setLineBreakMode:[self valueForThemeAttribute:@"line-break-mode" inState:themeState]];
[contentView setTextShadowColor:[self valueForThemeAttribute:@"text-shadow-color" inState:themeState]];
[contentView setTextShadowOffset:[self valueForThemeAttribute:@"text-shadow-offset" inState:themeState]];
[contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" inState:themeState]];
if (segment.image && segment.label)
[contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" inState:themeState]];
if ([segment image] && [segment label])
[contentView setImagePosition:[self valueForThemeAttribute:@"image-position" inState:themeState]];
else if (segment.image)
else if ([segment image])
[contentView setImagePosition:CPImageOnly];
if (i == count - 1)
continue;
var borderState = _themeStates[i] | _themeStates[i+1];
var borderState = _themeStates[i] | _themeStates[i + 1];
borderState = (borderState & CPThemeStateSelected & ~CPThemeStateHighlighted) ? CPThemeStateSelected : CPThemeStateNormal;
borderState |= _themeState & CPThemeStateDisabled;
var borderColor = [self valueForThemeAttribute:@"divider-bezel-color"
inState:borderState];
inState:borderState],
var borderView = [self layoutEphemeralSubviewNamed:"divider-bezel-"+i
positioned:CPWindowBelow
borderView = [self layoutEphemeralSubviewNamed:"divider-bezel-" + i
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil];
[borderView setBackgroundColor:borderColor];
@@ -609,48 +604,53 @@ CPSegmentSwitchTrackingMomentary = 2;
return;
var segment = _segments[aSegment],
segmentWidth = segment.width,
segmentWidth = [segment width],
themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled),
contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState],
font = [self valueForThemeAttribute:@"font" inState:themeState];
if (!segmentWidth)
{
if (segment.image && segment.label)
segmentWidth = [segment.label sizeWithFont:font].width + [segment.image size].width + contentInset.left + contentInset.right;
if ([segment image] && [segment label])
segmentWidth = [[segment label] sizeWithFont:font].width + [[segment image] size].width + contentInset.left + contentInset.right;
else if (segment.image)
segmentWidth = [segment.image size].width + contentInset.left + contentInset.right;
segmentWidth = [[segment image] size].width + contentInset.left + contentInset.right;
else if (segment.label)
segmentWidth = [segment.label sizeWithFont:font].width + contentInset.left + contentInset.right;
segmentWidth = [[segment label] sizeWithFont:font].width + contentInset.left + contentInset.right;
else
segmentWidth = 0.0;
}
var delta = segmentWidth - CGRectGetWidth(segment.frame);
var delta = segmentWidth - CGRectGetWidth([segment frame]);
if (!delta)
return;
{
[self setNeedsLayout];
[self setNeedsDisplay:YES];
// Update Contorl Size
return;
}
// Update control size
var frame = [self frame];
[self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))];
// Update Segment Width
segment.width = segmentWidth;
segment.frame = [self frameForSegment:aSegment];;
// Update segment width
[segment setWidth:segmentWidth];
[segment setFrame:[self frameForSegment:aSegment]];
// Update Following Segments Widths
// Update following segments widths
var index = aSegment + 1;
for (; index < _segments.length; ++index)
{
_segments[index].frame.origin.x += delta;
[_segments[index] frame].origin.x += delta;
[self drawSegmentBezel:index highlight:NO];
[self drawSegment:index highlight:NO];
}
[self drawSegmentBezel:aSegment highlight:NO];
[self drawSegment:aSegment highlight:NO];
@@ -696,14 +696,14 @@ CPSegmentSwitchTrackingMomentary = 2;
{
var location = [self convertPoint:aPoint fromView:nil],
count = _segments.length;
while (count--)
if (CGRectContainsPoint(_segments[count].frame, aPoint))
if (CGRectContainsPoint([_segments[count] frame], aPoint))
return count;
if (_segments.length)
{
var adjustedLastFrame = CGRectCreateCopy(_segments[_segments.length - 1].frame);
var adjustedLastFrame = CGRectCreateCopy([_segments[_segments.length - 1] frame]);
adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x;
if (CGRectContainsPoint(adjustedLastFrame, aPoint))
@@ -717,7 +717,7 @@ CPSegmentSwitchTrackingMomentary = 2;
{
if (![self isEnabled])
return;
[self trackSegment:anEvent];
}
@@ -731,10 +731,10 @@ CPSegmentSwitchTrackingMomentary = 2;
@param anEvent the event to handle
*/
- (void)trackSegment:(CPEvent)anEvent
{
{
var type = [anEvent type],
location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if (type == CPLeftMouseUp)
{
if (_trackingSegment == -1)
@@ -745,30 +745,30 @@ CPSegmentSwitchTrackingMomentary = 2;
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 = -1;
}
}
[self drawSegmentBezel:_trackingSegment highlight:NO];
_trackingSegment = -1;
return;
}
if (type == CPLeftMouseDown)
{
var trackingSegment = [self testSegment:location];
@@ -779,7 +779,7 @@ CPSegmentSwitchTrackingMomentary = 2;
[self drawSegmentBezel:_trackingSegment highlight:YES];
}
}
else if (type == CPLeftMouseDragged)
{
if (_trackingSegment == -1)
@@ -793,14 +793,14 @@ CPSegmentSwitchTrackingMomentary = 2;
[self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
}
}
[CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
- (void)setFont:(CPFont)aFont
{
[super setFont:aFont];
[self tileWithChangedSegment:0];
}
@@ -816,12 +816,12 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
var frame = [self frame],
originalWidth = frame.size.width;
frame.size.width = 0;
[self setFrame:frame];
@@ -832,38 +832,38 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
if ([aCoder containsValueForKey:CPSegmentedControlSelectedKey])
_selectedSegment = [aCoder decodeIntForKey:CPSegmentedControlSelectedKey];
else
else
_selectedSegment = -1;
if ([aCoder containsValueForKey:CPSegmentedControlTrackingModeKey])
_trackingMode = [aCoder decodeIntForKey:CPSegmentedControlTrackingModeKey];
else
_trackingMode = CPSegmentSwitchTrackingSelectOne;
// HACK
for (var i = 0; i < _segments.length; i++)
{
_themeStates[i] = _segments[i].selected ? CPThemeStateSelected : CPThemeStateNormal;
_themeStates[i] = [_segments[i] selected] ? CPThemeStateSelected : CPThemeStateNormal;
[self tileWithChangedSegment:i];
}
var difference = MAX(originalWidth - [self frame].size.width, 0.0),
remainingWidth = FLOOR(difference / _segments.length);
for (var i=0; i < _segments.length; i++)
[self setWidth:_segments[i].width + remainingWidth forSegment:i];
for (var i = 0; i < _segments.length; i++)
[self setWidth:[_segments[i] width] + remainingWidth forSegment:i];
[self tileWithChangedSegment:0];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_segments forKey:CPSegmentedControlSegmentsKey];
[aCoder encodeInt:_selectedSegment forKey:CPSegmentedControlSelectedKey];
[aCoder encodeInt:_segmentStyle forKey:CPSegmentedControlSegmentStyleKey];
@@ -875,15 +875,15 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
@implementation _CPSegmentItem : CPObject
{
CPImage image;
CPString label;
CPMenu menu;
BOOL selected;
BOOL enabled;
int tag;
int width;
CPImage image @accessors;
CPString label @accessors;
CPMenu menu @accessors;
BOOL selected @accessors;
BOOL enabled @accessors;
int tag @accessors;
int width @accessors;
CGRect frame;
CGRect frame @accessors;
}
- (id)init
@@ -894,8 +894,8 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
label = @"";
menu = nil;
selected = NO;
enabled = NO;
tag = 0;
enabled = YES;
tag = -1;
width = 0;
frame = CGRectMakeZero();
@@ -918,7 +918,7 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
image = [aCoder decodeObjectForKey:CPSegmentItemImageKey];
@@ -931,7 +931,7 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
frame = CGRectMakeZero();
}
return self;
}
@@ -947,4 +947,3 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
}
@end
+41 -18
View File
@@ -28,19 +28,17 @@
@import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
CPLightShadow = 0;
CPHeavyShadow = 1;
var CPShadowViewLightBackgroundColor = nil,
CPShadowViewHeavyBackgroundColor = nil;
var LIGHT_LEFT_INSET = 3.0,
LIGHT_RIGHT_INSET = 3.0,
LIGHT_TOP_INSET = 3.0,
LIGHT_BOTTOM_INSET = 5.0,
HEAVY_LEFT_INSET = 7.0,
HEAVY_RIGHT_INSET = 7.0,
HEAVY_TOP_INSET = 5.0,
@@ -61,51 +59,76 @@ var LIGHT_LEFT_INSET = 3.0,
return;
var bundle = [CPBundle bundleForClass:[self class]];
CPShadowViewLightBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTopLeft.png"] size:CGSizeMake(9.0, 9.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTop.png"] size:CGSizeMake(1.0, 9.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTopRight.png"] size:CGSizeMake(9.0, 9.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightLeft.png"] size:CGSizeMake(9.0, 1.0)],
nil,
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightRight.png"] size:CGSizeMake(9.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomLeft.png"] size:CGSizeMake(9.0, 9.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottom.png"] size:CGSizeMake(1.0, 9.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomRight.png"] size:CGSizeMake(9.0, 9.0)]
]]];
CPShadowViewHeavyBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTopLeft.png"] size:CGSizeMake(17.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTop.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTopRight.png"] size:CGSizeMake(17.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyLeft.png"] size:CGSizeMake(17.0, 1.0)],
nil,
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyRight.png"] size:CGSizeMake(17.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomLeft.png"] size:CGSizeMake(17.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottom.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomRight.png"] size:CGSizeMake(17.0, 17.0)]
]]];
}
+ (id)shadowViewEnclosingView:(CPView)aView
{
return [self shadowViewEnclosingView:aView withWeight:CPLightShadow];
}
+ (id)shadowViewEnclosingView:(CPView)aView withWeight:(CPShadowWeight)aWeight
{
var shadowView = [[CPShadowView alloc] initWithFrame:[aView frame]];
[shadowView setWeight:aWeight];
var size = [shadowView frame].size,
width = size.width - [shadowView leftInset] - [shadowView rightInset],
height = size.height - [shadowView topInset] - [shadowView bottomInset],
enclosingView = [aView superview];
[shadowView setHitTests:[aView hitTests]];
[shadowView setAutoresizingMask:[aView autoresizingMask]];
[aView removeFromSuperview];
[shadowView addSubview:aView];
[aView setFrame:CGRectMake([shadowView leftInset], [shadowView topInset], width, height)]
[enclosingView addSubview:shadowView];
return shadowView;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_weight = CPLightShadow;
[self setBackgroundColor:CPShadowViewLightBackgroundColor];
[self setHitTests:NO];
}
return self;
}
@@ -113,9 +136,9 @@ var LIGHT_LEFT_INSET = 3.0,
{
if (_weight == aWeight)
return;
_weight = aWeight;
if (_weight == CPLightShadow)
[self setBackgroundColor:CPShadowViewLightBackgroundColor];
@@ -147,7 +170,7 @@ var LIGHT_LEFT_INSET = 3.0,
{
if (_weight == CPLightShadow)
return LIGHT_LEFT_INSET + LIGHT_RIGHT_INSET;
return HEAVY_LEFT_INSET + HEAVY_RIGHT_INSET;
}
@@ -155,7 +178,7 @@ var LIGHT_LEFT_INSET = 3.0,
{
if (_weight == CPLightShadow)
return LIGHT_TOP_INSET + LIGHT_BOTTOM_INSET;
return HEAVY_TOP_INSET + HEAVY_BOTTOM_INSET;
}
+50 -40
View File
@@ -22,7 +22,6 @@
@import "CPControl.j"
#include "CoreGraphics/CGGeometry.h"
/*! SLIDER STATES */
@@ -42,7 +41,7 @@ CPCircularSlider = 1;
BOOL _isVertical;
}
+ (CPString)themeClass
+ (CPString)defaultThemeClass
{
return "slider";
}
@@ -61,14 +60,14 @@ CPCircularSlider = 1;
{
_minValue = 0.0;
_maxValue = 100.0;
[self setObjectValue:50.0];
[self setContinuous:YES];
[self _recalculateIsVertical];
}
return self;
}
@@ -76,11 +75,11 @@ CPCircularSlider = 1;
{
if (_minValue === aMinimumValue)
return;
_minValue = aMinimumValue;
var doubleValue = [self doubleValue];
if (doubleValue < _minValue)
[self setDoubleValue:_minValue];
@@ -98,11 +97,11 @@ CPCircularSlider = 1;
{
if (_maxValue === aMaximumValue)
return;
_maxValue = aMaximumValue;
var doubleValue = [self doubleValue];
if (doubleValue > _maxValue)
[self setDoubleValue:_maxValue];
@@ -169,27 +168,27 @@ CPCircularSlider = 1;
bounds.size.height = trackWidth;
}
}
return bounds;
}
- (CGRect)knobRectForBounds:(CGRect)bounds
{
var knobSize = [self currentValueForThemeAttribute:@"knob-size"];
if (knobSize.width <= 0 || knobSize.height <= 0)
return _CGRectMakeZero();
var knobRect = _CGRectMake(0.0, 0.0, knobSize.width, knobSize.height),
trackRect = [self trackRectForBounds:bounds];
// No track, do our best to approximate a place for this thing.
if (!trackRect || _CGRectIsEmpty(trackRect))
trackRect = bounds;
if ([self hasThemeState:CPThemeStateCircular])
{
var angle = 3*PI_2 - (1.0 - [self doubleValue] - _minValue) / (_maxValue - _minValue) * PI2,
var angle = 3 * PI_2 - (1.0 - [self doubleValue] - _minValue) / (_maxValue - _minValue) * PI2,
radius = CGRectGetWidth(trackRect) / 2.0 - 8.0;
knobRect.origin.x = radius * COS(angle) + CGRectGetMidX(trackRect) - 3.0;
@@ -198,7 +197,7 @@ CPCircularSlider = 1;
else if ([self isVertical])
{
knobRect.origin.x = _CGRectGetMidX(trackRect) - knobSize.width / 2.0;
knobRect.origin.y = (([self doubleValue] - _minValue) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
knobRect.origin.y = ((_maxValue - [self doubleValue]) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
}
else
{
@@ -213,10 +212,10 @@ CPCircularSlider = 1;
{
if (aName === "track-view")
return [self trackRectForBounds:[self bounds]];
else if (aName === "knob-view")
return [self knobRectForBounds:[self bounds]];
return [super rectForEphemeralSubviewNamed:aName];
}
@@ -225,12 +224,12 @@ CPCircularSlider = 1;
if (aName === "track-view" || aName === "knob-view")
{
var view = [[CPView alloc] init];
[view setHitTests:NO];
return view;
}
return [super createEphemeralSubviewNamed:aName];
}
@@ -256,7 +255,7 @@ CPCircularSlider = 1;
var bounds = [self bounds],
width = _CGRectGetWidth(bounds),
height = _CGRectGetHeight(bounds);
_isVertical = width < height ? 1 : (width > height ? 0 : -1);
if (_isVertical === 1)
@@ -282,7 +281,7 @@ CPCircularSlider = 1;
var knobView = [self layoutEphemeralSubviewNamed:@"knob-view"
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"track-view"];
if (knobView)
[knobView setBackgroundColor:[self currentValueForThemeAttribute:"knob-color"]];
}
@@ -320,7 +319,7 @@ CPCircularSlider = 1;
var minValue = [self minValue];
return MAX(0.0, MIN(1.0, (aPoint.y - _CGRectGetMinY(trackRect)) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
return MAX(0.0, MIN(1.0, (_CGRectGetMaxY(trackRect) - aPoint.y) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
}
else
{
@@ -339,44 +338,43 @@ CPCircularSlider = 1;
{
var bounds = [self bounds],
knobRect = [self knobRectForBounds:_CGRectMakeCopy(bounds)];
if (_CGRectContainsPoint(knobRect, aPoint))
_dragOffset = _CGSizeMake(_CGRectGetMidX(knobRect) - aPoint.x, _CGRectGetMidY(knobRect) - aPoint.y);
else
else
{
var trackRect = [self trackRectForBounds:bounds];
if (trackRect && _CGRectContainsPoint(trackRect, aPoint))
{
_dragOffset = _CGSizeMakeZero();
[self setObjectValue:[self _valueAtPoint:aPoint]];
}
else
return NO;
}
[self setHighlighted:YES];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
return YES;
return YES;
}
- (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
{
[self setObjectValue:[self _valueAtPoint:_CGPointMake(aPoint.x + _dragOffset.width, aPoint.y + _dragOffset.height)]];
return YES;
}
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
{
[self setHighlighted:NO];
if ([_target respondsToSelector:@selector(sliderDidFinish:)])
[_target sliderDidFinish:self];
@@ -392,10 +390,22 @@ CPCircularSlider = 1;
{
if (flag)
_sendActionOn |= CPLeftMouseDraggedMask;
else
else
_sendActionOn &= ~CPLeftMouseDraggedMask;
}
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
var count = objects.length,
value = [objects[0] valueForKeyPath:aKeyPath];
[self setObjectValue:value];
while (count-- > 1)
if (value !== ([objects[count] valueForKeyPath:aKeyPath]))
return [self setFloatValue:1.0];
}
@end
var CPSliderMinValueKey = "CPSliderMinValueKey",
@@ -442,14 +452,14 @@ var CPSliderMinValueKey = "CPSliderMinValueKey",
- (id)value
{
CPLog.warn("[CPSlider value] is deprecated, use doubleValue or objectValue instead.");
return [self doubleValue];
return [self doubleValue];
}
- (void)setValue:(id)aValue
{
CPLog.warn("[CPSlider setValue:] is deprecated, use setDoubleValue: or setObjectValue: instead.");
[self setObjectValue:aValue];
}
+103 -167
View File
@@ -20,8 +20,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPView.j"
@import "CPColorPicker.j"
/*
@ignore
*/
@@ -45,16 +47,15 @@
CPTextField _saturationLabel;
CPTextField _brightnessLabel;
CPTextField _hexLabel;
CPTextField _hexValue;
#if PLATFORM(DOM)
DOMElement _redValue;
DOMElement _greenValue;
DOMElement _blueValue;
DOMElement _hueValue;
DOMElement _saturationValue;
DOMElement _brightnessValue;
DOMElement _hexValue;
#endif
CPTextField _hexValue;
CPTextField _redValue;
CPTextField _greenValue;
CPTextField _blueValue;
CPTextField _hueValue;
CPTextField _saturationValue;
CPTextField _brightnessValue;
}
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
@@ -84,73 +85,13 @@
[_redSlider setAction: @selector(sliderChanged:)];
[_redSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM)
var updateFunction = function(aDOMEvent)
{
if(isNaN(this.value))
return;
switch(this)
{
case _redValue: [_redSlider setFloatValue:MAX(MIN(ROUND(this.value), 255) / 255.0, 0)];
//[self sliderChanged: _redSlider];
break;
case _greenValue: [_greenSlider setFloatValue:MAX(MIN(ROUND(this.value), 255) / 255.0, 0)];
//[self sliderChanged: _greenSlider];
break;
case _blueValue: [_blueSlider setFloatValue:MAX(MIN(ROUND(this.value), 255) / 255.0, 0)];
//[self sliderChanged: _blueSlider];
break;
case _hueValue: [_hueSlider setFloatValue:MAX(MIN(ROUND(this.value), 360), 0)];
//[self sliderChanged: _hueSlider];
break;
case _saturationValue: [_saturationSlider setFloatValue:MAX(MIN(ROUND(this.value), 100), 0)];
//[self sliderChanged: _saturationSlider];
break;
case _brightnessValue: [_brightnessSlider setFloatValue:MAX(MIN(ROUND(this.value), 100), 0)];
//[self sliderChanged: _brightnessSlider];
break;
}
this.blur();
};
var keypressFunction = function(aDOMEvent)
{
aDOMEvent = aDOMEvent || window.event;
if (aDOMEvent.keyCode == 13)
{
updateFunction(aDOMEvent);
if(aDOMEvent.preventDefault)
aDOMEvent.preventDefault();
else if(aDOMEvent.stopPropagation)
aDOMEvent.stopPropagation();
}
}
//red value input box
var redValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 35, 45, 20)];
[redValue setAutoresizingMask: CPViewMinXMargin];
_redValue = document.createElement("input");
_redValue.style.width = "40px";
_redValue.style.backgroundColor = "transparent";
_redValue.style.border = "1px solid black";
_redValue.style.color = "black";
_redValue.style.position = "absolute";
_redValue.style.top = "0px";
_redValue.style.left = "0px";
_redValue.onchange = updateFunction;
redValue._DOMElement.appendChild(_redValue);
[_contentView addSubview: redValue];
#endif
// red value input box
_redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 29)];
[_redValue setAutoresizingMask: CPViewMinXMargin];
[_redValue setEditable: YES];
[_redValue setBezeled: YES];
[_redValue setDelegate: self];
[_contentView addSubview: _redValue];
_greenLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 58, 15, 20)];
[_greenLabel setStringValue: "G"];
@@ -163,17 +104,13 @@
[_greenSlider setAction: @selector(sliderChanged:)];
[_greenSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM)
//green value input box
var greenValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 58, 45, 20)];
[greenValue setAutoresizingMask: CPViewMinXMargin];
_greenValue = _redValue.cloneNode(false);
_greenValue.onchange = updateFunction;
greenValue._DOMElement.appendChild(_greenValue);
[_contentView addSubview: greenValue];
#endif
// green value input box
_greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 53, 45, 29)];
[_greenValue setAutoresizingMask: CPViewMinXMargin];
[_greenValue setEditable: YES];
[_greenValue setBezeled: YES];
[_greenValue setDelegate: self];
[_contentView addSubview: _greenValue];
_blueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 81, 15, 20)];
[_blueLabel setStringValue: "B"];
@@ -186,17 +123,14 @@
[_blueSlider setAction: @selector(sliderChanged:)];
[_blueSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM)
//blue value input box
var blueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 81, 45, 20)];
[blueValue setAutoresizingMask: CPViewMinXMargin];
// blue value input box
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 76, 45, 29)];
[_blueValue setAutoresizingMask: CPViewMinXMargin];
[_blueValue setEditable: YES];
[_blueValue setBezeled: YES];
[_blueValue setDelegate: self];
[_contentView addSubview: _blueValue];
_blueValue = _redValue.cloneNode(false);
_blueValue.onchange = updateFunction;
blueValue._DOMElement.appendChild(_blueValue);
[_contentView addSubview: blueValue];
#endif
_hsbLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 120, 190, 20)];
[_hsbLabel setStringValue: "Hue, Saturation, Brightness"];
[_hsbLabel setTextColor:[CPColor blackColor]];
@@ -212,17 +146,14 @@
[_hueSlider setAction: @selector(sliderChanged:)];
[_hueSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM)
//red value input box
var hueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 145, 45, 20)];
[hueValue setAutoresizingMask: CPViewMinXMargin];
// hue value input box
_hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 140, 45, 29)];
[_hueValue setAutoresizingMask: CPViewMinXMargin];
[_hueValue setEditable: YES];
[_hueValue setBezeled: YES];
[_hueValue setDelegate: self];
[_contentView addSubview: _hueValue];
_hueValue = _redValue.cloneNode(false);
_hueValue.onchange = updateFunction;
hueValue._DOMElement.appendChild(_hueValue);
[_contentView addSubview: hueValue];
#endif
_saturationLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 168, 15, 20)];
[_saturationLabel setStringValue: "S"];
[_saturationLabel setTextColor:[CPColor blackColor]];
@@ -234,17 +165,14 @@
[_saturationSlider setAction: @selector(sliderChanged:)];
[_saturationSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM)
//green value input box
var saturationValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 168, 45, 20)];
[saturationValue setAutoresizingMask: CPViewMinXMargin];
// saturation value input box
_saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 163, 45, 29)];
[_saturationValue setAutoresizingMask: CPViewMinXMargin];
[_saturationValue setEditable: YES];
[_saturationValue setBezeled: YES];
[_saturationValue setDelegate: self];
[_contentView addSubview: _saturationValue];
_saturationValue = _redValue.cloneNode(false);
_saturationValue.onchange = updateFunction;
saturationValue._DOMElement.appendChild(_saturationValue);
[_contentView addSubview: saturationValue];
#endif
_brightnessLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 191, 15, 20)];
[_brightnessLabel setStringValue: "B"];
[_brightnessLabel setTextColor:[CPColor blackColor]];
@@ -256,51 +184,24 @@
[_brightnessSlider setAction: @selector(sliderChanged:)];
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM)
//blue value input box
var brightnessValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 191, 45, 20)];
[brightnessValue setAutoresizingMask: CPViewMinXMargin];
// brightness value input box
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 186, 45, 29)];
[_brightnessValue setAutoresizingMask: CPViewMinXMargin];
[_brightnessValue setEditable: YES];
[_brightnessValue setBezeled: YES];
[_brightnessValue setDelegate: self];
[_contentView addSubview: _brightnessValue];
_brightnessValue = _redValue.cloneNode(false);
_brightnessValue.onchange = updateFunction;
brightnessValue._DOMElement.appendChild(_brightnessValue);
[_contentView addSubview: brightnessValue];
#endif
_hexLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 230, 30, 20)];
[_hexLabel setStringValue: "Hex"];
[_hexLabel setTextColor:[CPColor blackColor]];
#if PLATFORM(DOM)
//hex input box
_hexValue = _redValue.cloneNode(false);
_hexValue.style.top = "228px";
_hexValue.style.width = "80px";
_hexValue.style.left = "35px";
_hexValue.onkeypress = function(aDOMEvent)
{
aDOMEvent = aDOMEvent || window.event;
if (aDOMEvent.keyCode == 13)
{
var newColor = [CPColor colorWithHexString: this.value];
if(newColor)
{
[self setColor: newColor];
[[self colorPanel] setColor: newColor];
}
if(aDOMEvent.preventDefault)
aDOMEvent.preventDefault();
else if(aDOMEvent.stopPropagation)
aDOMEvent.stopPropagation();
this.blur();
}
};
_contentView._DOMElement.appendChild(_hexValue);
#endif
_hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 29)];
[_hexValue setEditable: YES];
[_hexValue setBezeled: YES];
[_hexValue setDelegate: self];
[_contentView addSubview: _hexValue];
[_contentView addSubview: _rgbLabel];
[_contentView addSubview: _redLabel];
@@ -392,9 +293,7 @@
- (void)updateHex:(CPColor)aColor
{
#if PLATFORM(DOM)
_hexValue.value = [aColor hexString];
#endif
[_hexValue setStringValue:[aColor hexString]];
}
- (void)updateRGBSliders:(CPColor)aColor
@@ -408,15 +307,13 @@
- (void)updateLabels
{
#if PLATFORM(DOM)
_hueValue.value = ROUND([_hueSlider floatValue]);
_saturationValue.value = ROUND([_saturationSlider floatValue]);
_brightnessValue.value = ROUND([_brightnessSlider floatValue]);
[_hueValue setStringValue: ROUND([_hueSlider floatValue])];
[_saturationValue setStringValue: ROUND([_saturationSlider floatValue])];
[_brightnessValue setStringValue: ROUND([_brightnessSlider floatValue])];
_redValue.value = ROUND([_redSlider floatValue] * 255);
_greenValue.value = ROUND([_greenSlider floatValue] * 255);
_blueValue.value = ROUND([_blueSlider floatValue] * 255);
#endif
[_redValue setStringValue: ROUND([_redSlider floatValue] * 255)];
[_greenValue setStringValue: ROUND([_greenSlider floatValue] * 255)];
[_blueValue setStringValue: ROUND([_blueSlider floatValue] * 255)];
}
- (CPImage)provideNewButtonImage
@@ -429,4 +326,43 @@
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:CPColorPicker] pathForResource:"slider_button_h.png"] size:CGSizeMake(32, 32)];
}
- (void)controlTextDidEndEditing:(CPNotification)aNotification
{
var field = [aNotification object],
value = [[field stringValue] stringByTrimmingWhitespace];
if (field === _hexValue) {
var newColor = [CPColor colorWithHexString: value];
if (newColor) {
[self setColor: newColor];
[[self colorPanel] setColor: newColor];
}
} else {
switch(field) {
case _redValue: [_redSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
[self sliderChanged: _redSlider];
break;
case _greenValue: [_greenSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
[self sliderChanged: _greenSlider];
break;
case _blueValue: [_blueSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
[self sliderChanged: _blueSlider];
break;
case _hueValue: [_hueSlider setFloatValue:MAX(MIN(ROUND(value), 360), 0)];
[self sliderChanged: _hueSlider];
break;
case _saturationValue: [_saturationSlider setFloatValue:MAX(MIN(ROUND(value), 100), 0)];
[self sliderChanged: _saturationSlider];
break;
case _brightnessValue: [_brightnessSlider setFloatValue:MAX(MIN(ROUND(value), 100), 0)];
[self sliderChanged: _brightnessSlider];
break;
}
}
}
@end
+239 -83
View File
@@ -20,13 +20,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPButtonBar.j"
@import "CPImage.j"
@import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
#include "Platform/Platform.h"
#include "Platform/DOM/CPDOMDisplayServer.h"
CPSplitViewDidResizeSubviewsNotification = @"CPSplitViewDidResizeSubviewsNotification";
CPSplitViewWillResizeSubviewsNotification = @"CPSplitViewWillResizeSubviewsNotification";
@@ -43,18 +40,32 @@ var CPSplitViewHorizontalImage = nil,
id _delegate;
BOOL _isVertical;
BOOL _isPaneSplitter;
int _currentDivider;
float _initialOffset;
float _preCollapsePosition;
CPString _originComponent;
CPString _sizeComponent;
CPArray _DOMDividerElements;
CPString _dividerImagePath;
int _drawingDivider;
BOOL _needsResizeSubviews;
CPArray _buttonBars;
}
+ (CPString)defaultThemeClass
{
return @"splitview";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[10.0, 1.0, [CPColor grayColor]]
forKeys:[@"divider-thickness", @"pane-divider-thickness", @"pane-divider-color"]];
}
/*
@@ -77,16 +88,17 @@ var CPSplitViewHorizontalImage = nil,
_currentDivider = CPNotFound;
_DOMDividerElements = [];
_buttonBars = [];
[self _setVertical:YES];
}
return self;
}
- (float)dividerThickness
{
return _isPaneSplitter ? 1.0 : 10.0;
return [self currentValueForThemeAttribute:[self isPaneSplitter] ? @"pane-divider-thickness" : @"divider-thickness"];
}
- (BOOL)isVertical
@@ -98,7 +110,7 @@ var CPSplitViewHorizontalImage = nil,
{
if (![self _setVertical:shouldBeVertical])
return;
// Just re-adjust evenly.
var frame = [self frame],
dividerThickness = [self dividerThickness];
@@ -125,13 +137,13 @@ var CPSplitViewHorizontalImage = nil,
- (BOOL)_setVertical:(BOOL)shouldBeVertical
{
var changed = (_isVertical != shouldBeVertical);
_isVertical = shouldBeVertical;
_originComponent = [self isVertical] ? "x" : "y";
_sizeComponent = [self isVertical] ? "width" : "height";
_dividerImagePath = [self isVertical] ? [CPSplitViewVerticalImage filename] : [CPSplitViewHorizontalImage filename];
return changed;
}
@@ -147,10 +159,10 @@ var CPSplitViewHorizontalImage = nil,
_isPaneSplitter = shouldBePaneSplitter;
if(_DOMDividerElements[_drawingDivider])
[self _setupDOMDivider]
if (_DOMDividerElements[_drawingDivider])
[self _setupDOMDivider];
// The divider changes size when pane splitter mode is toggled, so the
// The divider changes size when pane splitter mode is toggled, so the
// subviews need to change size too.
_needsResizeSubviews = YES;
[self setNeedsDisplay:YES];
@@ -181,9 +193,8 @@ var CPSplitViewHorizontalImage = nil,
- (CGRect)effectiveRectOfDividerAtIndex:(int)aDivider
{
var realRect = [self rectOfDividerAtIndex:aDivider];
var padding = 2;
var realRect = [self rectOfDividerAtIndex:aDivider],
padding = 2;
realRect.size[_sizeComponent] += padding * 2;
realRect.origin[_originComponent] -= padding;
@@ -209,19 +220,13 @@ var CPSplitViewHorizontalImage = nil,
{
_DOMDividerElements[_drawingDivider] = document.createElement("div");
if(_isVertical)
_DOMDividerElements[_drawingDivider].style.cursor = [[CPCursor resizeLeftRightCursor] _cssString];
else
_DOMDividerElements[_drawingDivider].style.cursor = [[CPCursor resizeUpDownCursor] _cssString];
_DOMDividerElements[_drawingDivider].style.position = "absolute";
_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
@@ -231,7 +236,7 @@ var CPSplitViewHorizontalImage = nil,
{
if (_isPaneSplitter)
{
_DOMDividerElements[_drawingDivider].style.backgroundColor = "#A5A5A5";
_DOMDividerElements[_drawingDivider].style.backgroundColor = [[self currentValueForThemeAttribute:@"pane-divider-color"] cssString];
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
}
else
@@ -256,7 +261,7 @@ var CPSplitViewHorizontalImage = nil,
var subviews = [self subviews],
count = subviews.length,
oldSize = CGSizeMakeZero();
if ([self isVertical])
{
oldSize.width += [self dividerThickness] * (count - 1);
@@ -279,15 +284,25 @@ var CPSplitViewHorizontalImage = nil,
var frame = [_subviews[anIndex] frame],
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent],
effectiveRect = [self effectiveRectOfDividerAtIndex:anIndex],
buttonBar = _buttonBars[anIndex],
buttonBarRect = null,
additionalRect = null;
if (buttonBar != null)
{
buttonBarRect = [buttonBar resizeControlFrame];
buttonBarRect.origin = [self convertPoint:buttonBarRect.origin fromView:buttonBar];
}
if ([_delegate respondsToSelector:@selector(splitView:effectiveRect:forDrawnRect:ofDividerAtIndex:)])
effectiveRect = [_delegate splitView:self effectiveRect:effectiveRect forDrawnRect:effectiveRect ofDividerAtIndex:anIndex];
if ([_delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)])
additionalRect = [_delegate splitView:self additionalEffectiveRectOfDividerAtIndex:anIndex];
return CGRectContainsPoint(effectiveRect, aPoint) || (additionalRect && CGRectContainsPoint(additionalRect, aPoint));
return CGRectContainsPoint(effectiveRect, aPoint) ||
(additionalRect && CGRectContainsPoint(additionalRect, aPoint)) ||
(buttonBarRect && CGRectContainsPoint(buttonBarRect, aPoint));
}
- (CPView)hitTest:(CGPoint)aPoint
@@ -295,15 +310,15 @@ var CPSplitViewHorizontalImage = nil,
if ([self isHidden] || ![self hitTests] || !CGRectContainsPoint([self frame], aPoint))
return nil;
var point = [self convertPoint:aPoint fromView:[self superview]];
var point = [self convertPoint:aPoint fromView:[self superview]],
count = [_subviews count] - 1;
var count = [_subviews count] - 1;
for (var i = 0; i < count; i++)
{
if ([self cursorAtPoint:point hitDividerAtIndex:i])
return self;
}
return [super hitTest:aPoint];
}
@@ -320,12 +335,13 @@ var CPSplitViewHorizontalImage = nil,
if (_currentDivider != CPNotFound)
{
_currentDivider = CPNotFound;
[self _updateResizeCursor:anEvent];
[self _postNotificationDidResize];
}
return;
}
if (type == CPLeftMouseDown)
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
@@ -342,21 +358,21 @@ var CPSplitViewHorizontalImage = nil,
if ([anEvent clickCount] == 2 &&
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
[_delegate respondsToSelector:@selector(splitView:shouldCollapseSubview:forDoubleClickOnDividerAtIndex:)])
{
{
var minPosition = [self minPossiblePositionOfDividerAtIndex:i],
maxPosition = [self maxPossiblePositionOfDividerAtIndex:i];
if ([_delegate splitView:self canCollapseSubview:_subviews[i]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i] forDoubleClickOnDividerAtIndex:i])
{
if ([self isSubviewCollapsed:_subviews[i]])
[self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
[self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
else
[self setPosition:minPosition ofDividerAtIndex:i];
}
else if ([_delegate splitView:self canCollapseSubview:_subviews[i+1]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i+1] forDoubleClickOnDividerAtIndex:i])
else if ([_delegate splitView:self canCollapseSubview:_subviews[i + 1]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i + 1] forDoubleClickOnDividerAtIndex:i])
{
if ([self isSubviewCollapsed:_subviews[i+1]])
[self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
if ([self isSubviewCollapsed:_subviews[i + 1]])
[self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
else
[self setPosition:maxPosition ofDividerAtIndex:i];
}
@@ -374,14 +390,16 @@ var CPSplitViewHorizontalImage = nil,
if (_currentDivider === CPNotFound)
return;
}
else if (type == CPLeftMouseDragged && _currentDivider != CPNotFound)
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
[self setPosition:(point[_originComponent] + _initialOffset) ofDividerAtIndex:_currentDivider];
// Cursor might change if we reach a resize limit.
[self _updateResizeCursor:anEvent];
}
[CPApp setTarget:self selector:@selector(trackDivider:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
@@ -391,13 +409,89 @@ var CPSplitViewHorizontalImage = nil,
[self trackDivider:anEvent];
}
- (void)viewDidMoveToWindow
{
// Enable split view resize cursors. Commented out pending CPTrackingArea implementation.
//[[self window] setAcceptsMouseMovedEvents:YES];
}
- (void)mouseEntered:(CPEvent)anEvent
{
// Tracking code handles cursor by itself.
if (_currentDivider == CPNotFound)
[self _updateResizeCursor:anEvent];
}
- (void)mouseMoved:(CPEvent)anEvent
{
if (_currentDivider == CPNotFound)
[self _updateResizeCursor:anEvent];
}
- (void)mouseExited:(CPEvent)anEvent
{
if (_currentDivider == CPNotFound)
// FIXME: we should use CPCursor push/pop (if previous currentCursor != arrow).
[[CPCursor arrowCursor] set];
}
- (void)_updateResizeCursor:(CPEvent)anEvent
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if ([anEvent type] === CPLeftMouseUp && ![[self window] acceptsMouseMovedEvents])
{
[[CPCursor arrowCursor] set];
return;
}
for (var i = 0, count = [_subviews count] - 1; i < count; i++)
{
// If we are currently tracking, keep the resize cursor active even outside of hit areas.
if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i]))
{
var frame = [_subviews[i] frame],
size = frame.size[_sizeComponent],
startPosition = frame.origin[_originComponent] + size,
canShrink = [self _realPositionForPosition:startPosition - 1 ofDividerAtIndex:i] < startPosition,
canGrow = [self _realPositionForPosition:startPosition + 1 ofDividerAtIndex:i] > startPosition,
cursor = [CPCursor arrowCursor];
if (size === 0)
canGrow = YES; // Subview is collapsed.
else if (!canShrink &&
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
[_delegate splitView:self canCollapseSubview:_subviews[i]])
canShrink = YES; // Subview is collapsible.
if (_isVertical && canShrink && canGrow)
cursor = [CPCursor resizeLeftRightCursor];
else if (_isVertical && canShrink)
cursor = [CPCursor resizeLeftCursor];
else if (_isVertical && canGrow)
cursor = [CPCursor resizeRightCursor];
else if (canShrink && canGrow)
cursor = [CPCursor resizeUpDownCursor];
else if (canShrink)
cursor = [CPCursor resizeUpCursor];
else if (canGrow)
cursor = [CPCursor resizeDownCursor];
[cursor set];
return;
}
}
[[CPCursor arrowCursor] set];
}
- (float)maxPossiblePositionOfDividerAtIndex:(int)dividerIndex
{
var frame = [_subviews[dividerIndex + 1] frame];
if (dividerIndex + 1 < [_subviews count] - 1)
return frame.origin[_originComponent] + frame.size[_sizeComponent] - [self dividerThickness];
else
else
return [self frame].size[_sizeComponent] - [self dividerThickness];
}
@@ -406,17 +500,15 @@ var CPSplitViewHorizontalImage = nil,
if (dividerIndex > 0)
{
var frame = [_subviews[dividerIndex - 1] frame];
return frame.origin[_originComponent] + frame.size[_sizeComponent] + [self dividerThickness];
}
else
else
return 0;
}
- (void)setPosition:(float)position ofDividerAtIndex:(int)dividerIndex
- (int)_realPositionForPosition:(float)position ofDividerAtIndex:(int)dividerIndex
{
[self _adjustSubviewsWithCalculatedSize];
// not sure where this should override other positions?
if ([_delegate respondsToSelector:@selector(splitView:constrainSplitPosition:ofSubviewAt:)])
position = [_delegate splitView:self constrainSplitPosition:position ofSubviewAt:dividerIndex];
@@ -425,47 +517,64 @@ var CPSplitViewHorizontalImage = nil,
proposedMin = [self minPossiblePositionOfDividerAtIndex:dividerIndex],
actualMax = proposedMax,
actualMin = proposedMin;
if([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)])
if ([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)])
actualMin = [_delegate splitView:self constrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex];
if([_delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)])
if ([_delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)])
actualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
var frame = [self frame],
viewA = _subviews[dividerIndex],
frameA = [viewA frame],
viewB = _subviews[dividerIndex + 1],
frameB = [viewB frame];
var viewA = _subviews[dividerIndex],
realPosition = MAX(MIN(position, actualMax), actualMin);
var realPosition = MAX(MIN(position, actualMax), actualMin);
if (position < proposedMin + (actualMin - proposedMin) / 2)
if ([_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)])
if ([_delegate splitView:self canCollapseSubview:viewA])
realPosition = proposedMin;
return realPosition;
}
- (void)setPosition:(float)position ofDividerAtIndex:(int)dividerIndex
{
[self _adjustSubviewsWithCalculatedSize];
var realPosition = [self _realPositionForPosition:position ofDividerAtIndex:dividerIndex];
var viewA = _subviews[dividerIndex],
frameA = [viewA frame],
viewB = _subviews[dividerIndex + 1],
frameB = [viewB frame];
_preCollapsePosition = 0;
var preSize = frameA.size[_sizeComponent];
frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent];
if (preSize !== 0 && frameA.size[_sizeComponent] === 0)
_preCollapsePosition = preSize;
[_subviews[dividerIndex] setFrame:frameA];
preSize = frameB.size[_sizeComponent];
frameB.size[_sizeComponent] = frameB.origin[_originComponent] + frameB.size[_sizeComponent] - realPosition - [self dividerThickness];
if (preSize !== 0 && frameB.size[_sizeComponent] === 0)
_preCollapsePosition = preSize;
frameB.origin[_originComponent] = realPosition + [self dividerThickness];
[_subviews[dividerIndex + 1] setFrame:frameB];
[self setNeedsDisplay:YES];
}
- (void)setFrameSize:(CGSize)aSize
{
[self _adjustSubviewsWithCalculatedSize];
[super setFrameSize:aSize];
[self setNeedsDisplay:YES];
}
- (void)resizeSubviewsWithOldSize:(CPSize)oldSize
{
{
if ([_delegate respondsToSelector:@selector(splitView:resizeSubviewsWithOldSize:)])
{
[_delegate splitView:self resizeSubviewsWithOldSize:oldSize];
@@ -473,7 +582,7 @@ var CPSplitViewHorizontalImage = nil,
}
[self _postNotificationWillResize];
var index = 0,
count = [_subviews count],
bounds = [self bounds],
@@ -503,8 +612,8 @@ var CPSplitViewHorizontalImage = nil,
var nonSizableSpace = totalSizableSpace ? bounds.size[_sizeComponent] - totalSizableSpace : 0,
remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent],
oldDimension = (oldSize[_sizeComponent]- totalDividers*dividerThickness - nonSizableSpace),
ratio = oldDimension <= 0 ? 0 : (bounds.size[_sizeComponent] - totalDividers*dividerThickness - nonSizableSpace) / oldDimension;
oldDimension = (oldSize[_sizeComponent] - totalDividers * dividerThickness - nonSizableSpace),
ratio = oldDimension <= 0 ? 0 : (bounds.size[_sizeComponent] - totalDividers * dividerThickness - nonSizableSpace) / oldDimension;
for (index = 0; index < count; ++index)
{
@@ -524,7 +633,7 @@ var CPSplitViewHorizontalImage = nil,
else if (totalSizableSpace && !isSizable)
viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent];
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
[view setFrame:viewFrame];
}
@@ -538,7 +647,7 @@ var CPSplitViewHorizontalImage = nil,
[[CPNotificationCenter defaultCenter] removeObserver:_delegate name:CPSplitViewDidResizeSubviewsNotification object:self];
if ([_delegate respondsToSelector:@selector(splitViewWillResizeSubviews:)])
[[CPNotificationCenter defaultCenter] removeObserver:_delegate name:CPSplitViewWillResizeSubviewsNotification object:self];
_delegate = delegate;
if ([_delegate respondsToSelector:@selector(splitViewDidResizeSubviews:)])
@@ -553,6 +662,47 @@ var CPSplitViewHorizontalImage = nil,
object:self];
}
/*!
Set the button bar who's resize control should act as a control for this splitview.
Each divider can have at most one button bar assigned to it, and that button bar must be
a subview of one of the split view's subviews.
Calling this method with nil as the button bar will remove any currently assigned button bar
for the divider at that index. Indexes will not be adjusted as new subviews are added, so you
should usually call this method after adding all the desired subviews to the split view.
This method will automatically configure the hasResizeControl and resizeControlIsLeftAligned
parameters of the button bar, and will override any currently set values.
*/
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex
{
if (!aButtonBar)
{
_buttonBars[dividerIndex] = nil;
return;
}
var view = [aButtonBar superview],
subview = aButtonBar;
while (view && view !== self)
{
subview = view;
view = [view superview];
}
if (view !== self)
[CPException raise:CPInvalidArgumentException
reason:@"CPSplitView button bar must be a subview of the split view."];
var viewIndex = [[self subviews] indexOfObject:subview];
[aButtonBar setHasResizeControl:YES];
[aButtonBar setResizeControlIsLeftAligned:dividerIndex < viewIndex];
_buttonBars[dividerIndex] = aButtonBar;
}
- (void)_postNotificationWillResize
{
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewWillResizeSubviewsNotification object:self];
@@ -567,7 +717,8 @@ var CPSplitViewHorizontalImage = nil,
var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
CPSplitViewIsVerticalKey = "CPSplitViewIsVerticalKey",
CPSplitViewIsPaneSplitterKey = "CPSplitViewIsPaneSplitterKey";
CPSplitViewIsPaneSplitterKey = "CPSplitViewIsPaneSplitterKey",
CPSplitViewButtonBarsKey = "CPSplitViewButtonBarsKey";
@implementation CPSplitView (CPCoding)
@@ -578,19 +729,21 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
_currentDivider = CPNotFound;
_DOMDividerElements = [];
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];;
_buttonBars = [aCoder decodeObjectForKey:CPSplitViewButtonBarsKey] || [];
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];
_isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey];
[self _setVertical:[aCoder decodeBoolForKey:CPSplitViewIsVerticalKey]];
}
return self;
}
@@ -601,9 +754,12 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
//FIXME how should we handle this?
//[aCoder encodeObject:_buttonBars forKey:CPSplitViewButtonBarsKey];
[aCoder encodeConditionalObject:_delegate forKey:CPSplitViewDelegateKey];
[aCoder encodeBool:_isVertical forKey:CPSplitViewIsVerticalKey];
[aCoder encodeBool:_isPaneSplitter forKey:CPSplitViewIsPaneSplitterKey];
}
+25 -1
View File
@@ -25,8 +25,20 @@
@import "CPPlatformString.j"
var CPStringSizeWithFontInWidthCache = {};
CPStringSizeCachingEnabled = YES;
@implementation CPString (CPStringDrawing)
/*!
Returns a dictionary with the items "ascender", "descender", "lineHeight"
*/
+ (CPDictionary)metricsOfFont:(CPFont)aFont
{
return [CPPlatformString metricsOfFont:aFont];
}
/*!
Returns the string
*/
@@ -42,7 +54,19 @@
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
{
return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
if (!CPStringSizeCachingEnabled)
return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
var cacheKey = self + [aFont cssString] + aWidth,
size = CPStringSizeWithFontInWidthCache[cacheKey];
if (size === undefined)
{
size = [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
CPStringSizeWithFontInWidthCache[cacheKey] = size;
}
return CGSizeMakeCopy(size);
}
@end
+202 -553
View File
@@ -1,32 +1,8 @@
/*
* CPTabView.j
* AppKit
*
* Created by Francisco Tolmasky.
* Copyright 2008, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPImageView.j"
@import "CPBox.j"
@import "CPSegmentedControl.j"
@import "CPTabViewItem.j"
@import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
/*
Places tabs on top with a bezeled border.
@global
@@ -34,7 +10,7 @@
*/
CPTopTabsBezelBorder = 0;
//CPLeftTabsBezelBorder = 1;
//CPBottomTabsBezelBorder = 2;
CPBottomTabsBezelBorder = 2;
//CPRightTabsBezelBorder = 3;
/*
Displays no tabs and has a bezeled border.
@@ -55,173 +31,55 @@ CPNoTabsLineBorder = 5;
*/
CPNoTabsNoBorder = 6;
var CPTabViewBezelBorderLeftImage = nil,
CPTabViewBackgroundCenterImage = nil,
CPTabViewBezelBorderRightImage = nil,
CPTabViewBezelBorderColor = nil,
CPTabViewBezelBorderBackgroundColor = nil;
var LEFT_INSET = 7.0,
RIGHT_INSET = 7.0;
var CPTabViewDidSelectTabViewItemSelector = 1,
CPTabViewShouldSelectTabViewItemSelector = 2,
CPTabViewWillSelectTabViewItemSelector = 4,
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
/*!
@ingroup appkit
@class CPTabView
var HEIGHT_OF_SEGMENTED_CONTROL = 24;
This class represents a view that has multiple subviews (CPTabViewItem) presented as individual tabs.
Only one CPTabViewItem is shown at a time, and other CPTabViewItems can be made visible
(one at a time) by clicking on the CPTabViewItem's tab at the top of the tab view.
THe currently selected CPTabViewItem is the view that is displayed.
*/
@implementation CPTabView : CPView
{
CPView _labelsView;
CPView _backgroundView;
CPView _separatorView;
CPView _auxiliaryView;
CPView _contentView;
CPArray _tabViewItems;
CPTabViewItem _selectedTabViewItem;
CPArray items;
CPTabViewType _tabViewType;
id _delegate;
unsigned _delegateSelectors;
}
CPSegmentedControl tabs;
CPBox box;
/*
@ignore
*/
+ (void)initialize
{
if (self != CPTabView)
return;
var bundle = [CPBundle bundleForClass:self],
emptyImage = [[CPImage alloc] initByReferencingFile:@"" size:CGSizeMake(7.0, 0.0)],
backgroundImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBackgroundCenter.png"] size:CGSizeMake(1.0, 1.0)],
bezelBorderLeftImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBorderLeft.png"] size:CGSizeMake(7.0, 1.0)],
bezerBorderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBorder.png"] size:CGSizeMake(1.0, 1.0)],
bezelBorderRightImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBorderRight.png"] size:CGSizeMake(7.0, 1.0)];
CPTabViewBezelBorderBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
[
emptyImage,
emptyImage,
emptyImage,
CPNumber selectedIndex;
bezelBorderLeftImage,
backgroundImage,
bezelBorderRightImage,
CPTabViewType type;
bezelBorderLeftImage,
bezerBorderImage,
bezelBorderRightImage
]]];
CPTabViewBezelBorderColor = [CPColor colorWithPatternImage:bezerBorderImage];
}
/*
@ignore
*/
+ (CPColor)bezelBorderColor
{
return CPTabViewBezelBorderColor;
id delegate;
unsigned delegateSelectors;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_tabViewType = CPTopTabsBezelBorder;
_tabViewItems = [];
items = [CPArray array];
tabs = [[CPSegmentedControl alloc] initWithFrame:CGRectMake(0, 0, 0, HEIGHT_OF_SEGMENTED_CONTROL)];
[tabs setHitTests:NO];
box = [[CPBox alloc] initWithFrame:CGRectMake(0, HEIGHT_OF_SEGMENTED_CONTROL / 2, CGRectGetWidth(aFrame),
CGRectGetHeight(aFrame) - HEIGHT_OF_SEGMENTED_CONTROL)];
selectedIndex = CPNotFound;
[self setTabViewType:CPTopTabsBezelBorder];
[self setBackgroundColor:[CPColor colorWithCalibratedWhite:0.95 alpha:1.0]];
[self addSubview:box];
[self addSubview:tabs];
[box setAutoresizingMask:CPViewWidthSizable];
[tabs setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin];
}
return self;
}
- (void)viewDidMoveToWindow
{
if (_tabViewType != CPTopTabsBezelBorder || _labelsView)
return;
[self _createBezelBorder];
[self layoutSubviews];
}
/* @ignore */
- (void)_createBezelBorder
{
var bounds = [self bounds];
_labelsView = [[_CPTabLabelsView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), 0.0)];
[_labelsView setTabView:self];
[_labelsView setAutoresizingMask:CPViewWidthSizable];
[self addSubview:_labelsView];
_backgroundView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
[_backgroundView setBackgroundColor:CPTabViewBezelBorderBackgroundColor];
[_backgroundView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[self addSubview:_backgroundView];
_separatorView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
[_separatorView setBackgroundColor:[[self class] bezelBorderColor]];
[_separatorView setAutoresizingMask:CPViewWidthSizable | CPViewMaxYMargin];
[self addSubview:_separatorView];
}
/*
Lays out the subviews
@ignore
*/
- (void)layoutSubviews
{
if (_tabViewType == CPTopTabsBezelBorder)
{
var backgroundRect = [self bounds],
labelsViewHeight = [_CPTabLabelsView height];
backgroundRect.origin.y += labelsViewHeight;
backgroundRect.size.height -= labelsViewHeight;
[_backgroundView setFrame:backgroundRect];
var auxiliaryViewHeight = 5.0;
if (_auxiliaryView)
{
auxiliaryViewHeight = CGRectGetHeight([_auxiliaryView frame]);
[_auxiliaryView setFrame:CGRectMake(LEFT_INSET, labelsViewHeight, CGRectGetWidth(backgroundRect) - LEFT_INSET - RIGHT_INSET, auxiliaryViewHeight)];
}
[_separatorView setFrame:CGRectMake(LEFT_INSET, labelsViewHeight + auxiliaryViewHeight, CGRectGetWidth(backgroundRect) - LEFT_INSET - RIGHT_INSET, 1.0)];
}
// CPNoTabsNoBorder
[_contentView setFrame:[self contentRect]];
}
// Adding and Removing Tabs
/*!
Adds a CPTabViewItem to the tab view.
@@ -229,7 +87,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (void)addTabViewItem:(CPTabViewItem)aTabViewItem
{
[self insertTabViewItem:aTabViewItem atIndex:[_tabViewItems count]];
[self insertTabViewItem:aTabViewItem atIndex:[items count]];
}
/*!
@@ -240,20 +98,13 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(unsigned)anIndex
{
if (!_labelsView && _tabViewType == CPTopTabsBezelBorder)
[self _createBezelBorder];
[_tabViewItems insertObject:aTabViewItem atIndex:anIndex];
[_labelsView tabView:self didAddTabViewItem:aTabViewItem];
[aTabViewItem _setTabView:self];
if ([_tabViewItems count] == 1)
[self selectFirstTabViewItem:self];
[items insertObject:aTabViewItem atIndex:anIndex];
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
[self _updateItems];
[self _repositionTabs];
if (delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[delegate tabViewDidChangeNumberOfTabViewItems:self];
}
/*!
@@ -262,16 +113,19 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (void)removeTabViewItem:(CPTabViewItem)aTabViewItem
{
var index = [self indexOfTabViewItem:aTabViewItem];
for (var i = 0; i < [items count]; i++)
{
if ([items objectAtIndex:i] === aTabViewItem)
{
[items removeObjectAtIndex:i];
}
}
[_tabViewItems removeObjectIdenticalTo:aTabViewItem];
[_labelsView tabView:self didRemoveTabViewItemAtIndex:index];
[aTabViewItem _setTabView:nil];
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
[self _updateItems];
[self _repositionTabs];
if (delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[delegate tabViewDidChangeNumberOfTabViewItems:self];
}
// Accessing Tabs
@@ -281,7 +135,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem
{
return [_tabViewItems indexOfObjectIdenticalTo:aTabViewItem];
return [items indexOfObjectIdenticalTo:aTabViewItem];
}
/*!
@@ -290,14 +144,11 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier
{
var index = 0,
count = [_tabViewItems count];
for (; index < count; ++index)
if ([[_tabViewItems[index] identifier] isEqual:anIdentifier])
for (var index = [items count]; index >= 0; index--)
if ([[items[index] identifier] isEqual:anIdentifier])
return index;
return index;
return CPNotFound;
}
/*!
@@ -305,7 +156,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (unsigned)numberOfTabViewItems
{
return [_tabViewItems count];
return [items count];
}
/*!
@@ -313,7 +164,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (CPTabViewItem)tabViewItemAtIndex:(unsigned)anIndex
{
return _tabViewItems[anIndex];
return [items objectAtIndex:anIndex];
}
/*!
@@ -321,7 +172,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (CPArray)tabViewItems
{
return _tabViewItems;
return [items copy]; // Copy?
}
// Selecting a Tab
@@ -331,10 +182,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (void)selectFirstTabViewItem:(id)aSender
{
var count = [_tabViewItems count];
if (count)
[self selectTabViewItemAtIndex:0];
if ([items count] === 0)
return; // throw?
[self selectTabViewItemAtIndex:0];
}
/*!
@@ -343,10 +194,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (void)selectLastTabViewItem:(id)aSender
{
var count = [_tabViewItems count];
if (count)
[self selectTabViewItemAtIndex:count - 1];
if ([items count] === 0)
return; // throw?
[self selectTabViewItemAtIndex:[items count] - 1];
}
/*!
@@ -355,13 +206,16 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (void)selectNextTabViewItem:(id)aSender
{
if (!_selectedTabViewItem)
if (selectedIndex === CPNotFound)
return;
var index = [self indexOfTabViewItem:_selectedTabViewItem],
count = [_tabViewItems count];
[self selectTabViewItemAtIndex:index + 1 % count];
var nextIndex = selectedIndex + 1;
if (nextIndex === [items count])
// does nothing. According to spec at (http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSTabView_Class/Reference/Reference.html#//apple_ref/occ/instm/NSTabView/selectNextTabViewItem:)
return;
[self selectTabViewItemAtIndex:nextIndex];
}
/*!
@@ -370,13 +224,15 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (void)selectPreviousTabViewItem:(id)aSender
{
if (!_selectedTabViewItem)
if (selectedIndex === CPNotFound)
return;
var index = [self indexOfTabViewItem:_selectedTabViewItem],
count = [_tabViewItems count];
[self selectTabViewItemAtIndex:index == 0 ? count : index - 1];
var previousIndex = selectedIndex - 1;
if (previousIndex < 0)
return; // does nothing. See above.
[self selectTabViewItemAtIndex:previousIndex];
}
/*!
@@ -385,41 +241,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (void)selectTabViewItem:(CPTabViewItem)aTabViewItem
{
if ((_delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![_delegate tabView:self shouldSelectTabViewItem:aTabViewItem])
return;
if (_delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
[_delegate tabView:self willSelectTabViewItem:aTabViewItem];
if (_selectedTabViewItem)
{
_selectedTabViewItem._tabState = CPBackgroundTab;
[_labelsView tabView:self didChangeStateOfTabViewItem:_selectedTabViewItem];
[_contentView removeFromSuperview];
[_auxiliaryView removeFromSuperview];
}
_selectedTabViewItem = aTabViewItem;
_selectedTabViewItem._tabState = CPSelectedTab;
_contentView = [_selectedTabViewItem view];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
_auxiliaryView = [_selectedTabViewItem auxiliaryView];
[_auxiliaryView setAutoresizingMask:CPViewWidthSizable];
[self addSubview:_contentView];
if (_auxiliaryView)
[self addSubview:_auxiliaryView];
[_labelsView tabView:self didChangeStateOfTabViewItem:_selectedTabViewItem];
[self layoutSubviews];
if (_delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
[_delegate tabView:self didSelectTabViewItem:aTabViewItem];
[self selectTabViewItemAtIndex:[self indexOfTabViewItem:aTabViewItem]];
}
/*!
@@ -428,7 +250,24 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (void)selectTabViewItemAtIndex:(unsigned)anIndex
{
[self selectTabViewItem:_tabViewItems[anIndex]];
var aTabViewItem = [items objectAtIndex:anIndex];
if (anIndex === selectedIndex)
return;
var aTabViewItem = [self tabViewItemAtIndex:anIndex];
if ((delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![delegate tabView:self shouldSelectTabViewItem:aTabViewItem])
return;
if (delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
[delegate tabView:self willSelectTabViewItem:aTabViewItem];
[tabs selectSegmentWithTag:anIndex];
[self _setSelectedIndex:anIndex];
if (delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
[delegate tabView:self didSelectTabViewItem:aTabViewItem];
}
/*!
@@ -436,32 +275,43 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (CPTabViewItem)selectedTabViewItem
{
return _selectedTabViewItem;
return [items objectAtIndex:selectedIndex];
}
//
//
/*!
Sets the tab view type.
@param aTabViewType the view type
*/
- (void)setTabViewType:(CPTabViewType)aTabViewType
{
if (_tabViewType == aTabViewType)
if (type === aTabViewType)
return;
_tabViewType = aTabViewType;
if (_tabViewType == CPNoTabsBezelBorder || _tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder)
[_labelsView removeFromSuperview];
else if (![_labelsView superview])
[self addSubview:_labelsView];
if (_tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder)
[_backgroundView removeFromSuperview];
else if (![_backgroundView superview])
[self addSubview:_backgroundView];
[self layoutSubviews];
if ((type === CPTopTabsBezelBorder || type === CPBottomTabsBezelBorder)
&& (aTabViewType !== CPTopTabsBezelBorder && aTabViewType !== CPBottomTabsBezelBorder))
[tabs removeFromSuperview];
if ((type === CPNoTabsBezelBorder || type === CPNoTabsLineBorder || type === CPNoTabsNoBorder)
&& (aTabViewType !== CPNoTabsBezelBorder && aTabViewType !== CPNoTabsBezelBorder && aTabViewType !== CPNoTabsNoBorder))
[self addSubview:tabs];
type = aTabViewType;
switch (type)
{
case CPTopTabsBezelBorder:
case CPBottomTabsBezelBorder:
case CPNoTabsBezelBorder:
[box setBorderType:CPBezelBorder];
break;
case CPNoTabsLineBorder:
[box setBorderType:CPLineBorder];
break;
case CPNoTabsNoBorder:
[box setBorderType:CPNoBorder];
break;
}
}
/*!
@@ -469,31 +319,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (CPTabViewType)tabViewType
{
return _tabViewType;
}
// Determining the Size
/*!
Returns the content rectangle.
*/
- (CGRect)contentRect
{
var contentRect = CGRectMakeCopy([self bounds]);
if (_tabViewType == CPTopTabsBezelBorder)
{
var labelsViewHeight = [_CPTabLabelsView height],
auxiliaryViewHeight = _auxiliaryView ? CGRectGetHeight([_auxiliaryView frame]) : 5.0,
separatorViewHeight = 1.0;
contentRect.origin.y += labelsViewHeight + auxiliaryViewHeight + separatorViewHeight;
contentRect.size.height -= labelsViewHeight + auxiliaryViewHeight + separatorViewHeight * 2.0; // 2 for the bottom border as well.
contentRect.origin.x += LEFT_INSET;
contentRect.size.width -= LEFT_INSET + RIGHT_INSET;
}
return contentRect;
return type;
}
/*!
@@ -501,7 +327,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (id)delegate
{
return _delegate;
return delegate;
}
/*!
@@ -510,35 +336,74 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (void)setDelegate:(id)aDelegate
{
if (_delegate == aDelegate)
if (delegate == aDelegate)
return;
_delegate = aDelegate;
_delegateSelectors = 0;
if ([_delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)])
_delegateSelectors |= CPTabViewShouldSelectTabViewItemSelector;
delegate = aDelegate;
if ([_delegate respondsToSelector:@selector(tabView:willSelectTabViewItem:)])
_delegateSelectors |= CPTabViewWillSelectTabViewItemSelector;
delegateSelectors = 0;
if ([_delegate respondsToSelector:@selector(tabView:didSelectTabViewItem:)])
_delegateSelectors |= CPTabViewDidSelectTabViewItemSelector;
if ([delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)])
delegateSelectors |= CPTabViewShouldSelectTabViewItemSelector;
if ([_delegate respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)])
_delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector;
if ([delegate respondsToSelector:@selector(tabView:willSelectTabViewItem:)])
delegateSelectors |= CPTabViewWillSelectTabViewItemSelector;
if ([delegate respondsToSelector:@selector(tabView:didSelectTabViewItem:)])
delegateSelectors |= CPTabViewDidSelectTabViewItemSelector;
if ([delegate respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)])
delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector;
}
//
- (void)setBackgroundColor:(CPColor)aColor
{
[box setBackgroundColor:aColor];
}
- (void)mouseDown:(CPEvent)anEvent
{
var location = [_labelsView convertPoint:[anEvent locationInWindow] fromView:nil],
tabViewItem = [_labelsView representedTabViewItemAtPoint:location];
if (tabViewItem)
[self selectTabViewItem:tabViewItem];
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,
verticalCenterOfTabs = CGRectGetHeight([tabs bounds]) / 2;
if (type === CPBottomTabsBezelBorder)
[tabs setCenter:CGPointMake(horizontalCenterOfSelf, CGRectGetHeight([self bounds]) - verticalCenterOfTabs)];
else
[tabs setCenter:CGPointMake(horizontalCenterOfSelf, verticalCenterOfTabs)];
}
- (void)_setSelectedIndex:(CPNumber)index
{
selectedIndex = index;
[box setContentView:[[items objectAtIndex:selectedIndex] view]];
}
- (void)_updateItems
{
[tabs setSegmentCount:[items count]];
for (var i = 0; i < [items count]; i++)
{
[tabs setLabel:[[items objectAtIndex:i] label] forSegment:i];
[tabs setTag:i forSegment:i];
}
if (selectedIndex === CPNotFound)
{
[self selectFirstTabViewItem:self];
}
}
@end
@@ -554,20 +419,17 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
{
if (self = [super initWithCoder:aCoder])
{
_tabViewType = [aCoder decodeIntForKey:CPTabViewTypeKey];
_tabViewItems = [];
// FIXME: this is somewhat hacky
[self _createBezelBorder];
var items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
for (var i = 0; items && i < items.length; i++)
[self insertTabViewItem:items[i] atIndex:i];
type = [aCoder decodeIntForKey:CPTabViewTypeKey];
items = [];
var encodedItems = [aCoder decodeObjectForKey:CPTabViewItemsKey];
for (var i = 0; encodedItems && i < encodedItems.length; i++)
[self insertTabViewItem:encodedItems[i] atIndex:i];
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
if (selected)
[self selectTabViewItem:selected];
[self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
}
@@ -576,227 +438,14 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
- (void)encodeWithCoder:(CPCoder)aCoder
{
var actualSubviews = _subviews;
_subviews = [];
[super encodeWithCoder:aCoder];
_subviews = actualSubviews;
[aCoder encodeObject:_tabViewItems forKey:CPTabViewItemsKey];;
[aCoder encodeObject:_selectedTabViewItem forKey:CPTabViewSelectedItemKey];
[aCoder encodeInt:_tabViewType forKey:CPTabViewTypeKey];
[aCoder encodeConditionalObject:_delegate forKey:CPTabViewDelegateKey];
}
@end
var _CPTabLabelsViewBackgroundColor = nil,
_CPTabLabelsViewInsideMargin = 10.0,
_CPTabLabelsViewOutsideMargin = 15.0;
/* @ignore */
@implementation _CPTabLabelsView : CPView
{
CPTabView _tabView;
CPDictionary _tabLabels;
}
+ (void)initialize
{
if (self != [_CPTabLabelsView class])
return;
var bundle = [CPBundle bundleForClass:self];
_CPTabLabelsViewBackgroundColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelsViewLeft.png"] size:CGSizeMake(12.0, 26.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelsViewCenter.png"] size:CGSizeMake(1.0, 26.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelsViewRight.png"] size:CGSizeMake(12.0, 26.0)]
] isVertical:NO]];
}
+ (float)height
{
return 26.0;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_tabLabels = [];
[self setBackgroundColor:_CPTabLabelsViewBackgroundColor];
[self setFrameSize:CGSizeMake(CGRectGetWidth(aFrame), 26.0)];
}
return self;
}
- (void)setTabView:(CPTabView)aTabView
{
_tabView = aTabView;
}
- (CPTabView)tabView
{
return _tabView;
}
- (void)tabView:(CPTabView)aTabView didAddTabViewItem:(CPTabViewItem)aTabViewItem
{
var label = [[_CPTabLabel alloc] initWithFrame:CGRectMakeZero()];
[label setTabViewItem:aTabViewItem];
_tabLabels.push(label);
[self addSubview:label];
[self layoutSubviews];
}
- (void)tabView:(CPTabView)aTabView didRemoveTabViewItemAtIndex:(unsigned)index
{
var label = _tabLabels[index];
[_tabLabels removeObjectAtIndex:index];
[label removeFromSuperview];
[self layoutSubviews];
}
-(void)tabView:(CPTabView)aTabView didChangeStateOfTabViewItem:(CPTabViewItem)aTabViewItem
{
[_tabLabels[[aTabView indexOfTabViewItem:aTabViewItem]] setTabState:[aTabViewItem tabState]];
}
- (CPTabViewItem)representedTabViewItemAtPoint:(CGPoint)aPoint
{
var index = 0,
count = _tabLabels.length;
for (; index < count; ++index)
{
var label = _tabLabels[index];
if (CGRectContainsPoint([label frame], aPoint))
return [label tabViewItem];
}
return nil;
}
- (void)layoutSubviews
{
var index = 0,
count = _tabLabels.length,
width = (_CGRectGetWidth([self bounds]) - (count - 1) * _CPTabLabelsViewInsideMargin - 2 * _CPTabLabelsViewOutsideMargin) / count,
x = _CPTabLabelsViewOutsideMargin;
for (; index < count; ++index)
{
var label = _tabLabels[index],
frame = _CGRectMake(x, 8.0, width, 18.0);
[label setFrame:frame];
x = _CGRectGetMaxX(frame) + _CPTabLabelsViewInsideMargin;
}
}
- (void)setFrameSize:(CGSize)aSize
{
if (CGSizeEqualToSize([self frame].size, aSize))
return;
[super setFrameSize:aSize];
[self layoutSubviews];
}
@end
var _CPTabLabelBackgroundColor = nil,
_CPTabLabelSelectedBackgroundColor = nil;
/* @ignore */
@implementation _CPTabLabel : CPView
{
CPTabViewItem _tabViewItem;
CPTextField _labelField;
}
+ (void)initialize
{
if (self != [_CPTabLabel class])
return;
var bundle = [CPBundle bundleForClass:self];
_CPTabLabelBackgroundColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelBackgroundLeft.png"] size:CGSizeMake(6.0, 18.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelBackgroundCenter.png"] size:CGSizeMake(1.0, 18.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelBackgroundRight.png"] size:CGSizeMake(6.0, 18.0)]
] isVertical:NO]];
_CPTabLabelSelectedBackgroundColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelSelectedLeft.png"] size:CGSizeMake(3.0, 18.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelSelectedCenter.png"] size:CGSizeMake(1.0, 18.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelSelectedRight.png"] size:CGSizeMake(3.0, 18.0)]
] isVertical:NO]];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_labelField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_labelField setAlignment:CPCenterTextAlignment];
[_labelField setFrame:CGRectMake(5.0, 0.0, CGRectGetWidth(aFrame) - 10.0, 20.0)];
[_labelField setAutoresizingMask:CPViewWidthSizable];
[_labelField setFont:[CPFont boldSystemFontOfSize:11.0]];
[self addSubview:_labelField];
[self setTabState:CPBackgroundTab];
}
return self;
}
- (void)setTabState:(CPTabState)aTabState
{
[self setBackgroundColor:aTabState == CPSelectedTab ? _CPTabLabelSelectedBackgroundColor : _CPTabLabelBackgroundColor];
}
- (void)setTabViewItem:(CPTabViewItem)aTabViewItem
{
_tabViewItem = aTabViewItem;
[self update];
}
- (CPTabViewItem)tabViewItem
{
return _tabViewItem;
}
- (void)update
{
[_labelField setStringValue:[_tabViewItem label]];
[aCoder encodeObject:items forKey:CPTabViewItemsKey];;
[aCoder encodeObject:[self selectedTabViewItem] forKey:CPTabViewSelectedItemKey];
[aCoder encodeInt:type forKey:CPTabViewTypeKey];
[aCoder encodeConditionalObject:delegate forKey:CPTabViewDelegateKey];
}
@end
+1 -1
View File
@@ -22,7 +22,7 @@
@import <Foundation/CPObject.j>
@import <AppKit/CPView.j>
@import "CPView.j"
/*
+112 -28
View File
@@ -22,12 +22,12 @@
@import <Foundation/CPDictionary.j>
@import <Foundation/CPObject.j>
@import <Foundation/CPIndexSet.j>
@import <Foundation/CPSortDescriptor.j>
@import <Foundation/CPString.j>
@import "CPTableHeaderView.j"
#include "CoreGraphics/CGGeometry.h"
CPTableColumnNoResizing = 0;
CPTableColumnAutoresizingMask = 1 << 0;
@@ -50,7 +50,7 @@ CPTableColumnUserResizingMask = 1 << 1;
CPSortDescriptor _sortDescriptorPrototype;
BOOL _isHidden;
CPString _headerToolTip;
BOOL _disableResizingPosting @accessors(property=disableResizingPosting);
}
@@ -72,19 +72,13 @@ CPTableColumnUserResizingMask = 1 << 1;
_maxWidth = 1000000.0;
_resizingMask = CPTableColumnAutoresizingMask | CPTableColumnUserResizingMask;
_disableResizingPosting = NO;
[self setIdentifier:anIdentifier];
var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()];
[self setHeaderView:header];
var textDataView = [CPTextField new];
[textDataView setLineBreakMode:CPLineBreakByTruncatingTail];
[textDataView setValue:[CPColor colorWithHexString:@"333333"] forThemeAttribute:@"text-color"];
[textDataView setValue:[CPColor whiteColor] forThemeAttribute:@"text-color" inState:CPThemeStateHighlighted];
[textDataView setValue:[CPFont boldSystemFontOfSize:12] forThemeAttribute:@"font" inState:CPThemeStateHighlighted];
[textDataView setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
[self setDataView:textDataView];
[self setDataView:[CPTextField new]];
}
return self;
@@ -123,19 +117,19 @@ CPTableColumnUserResizingMask = 1 << 1;
{
var index = [[tableView tableColumns] indexOfObjectIdenticalTo:self],
dirtyTableColumnRangeIndex = tableView._dirtyTableColumnRangeIndex;
if (dirtyTableColumnRangeIndex < 0)
tableView._dirtyTableColumnRangeIndex = index;
else
tableView._dirtyTableColumnRangeIndex = MIN(index, tableView._dirtyTableColumnRangeIndex);
var rows = tableView._exposedRows,
columns = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(index, [tableView._exposedColumns lastIndex] - index + 1)];
columns = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(index, [tableView._exposedColumns lastIndex] - index + 1)];
// FIXME: Would be faster with some sort of -setNeedsDisplayInColumns: that updates a dirtyTableColumnForDisplay cache; then marked columns would relayout their data views at display time.
[tableView _layoutDataViewsInRows:rows columns:columns];
[tableView tile];
if (!_disableResizingPosting)
[self _postDidResizeNotificationWithOldWidth:oldWidth];
}
@@ -232,12 +226,12 @@ CPTableColumnUserResizingMask = 1 << 1;
/*!
This method set's the "prototype" view which will be used to create all table cells in this column.
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
Example:
[tableColumn setDataView:someView]; // snapshot taken
[[tableColumn dataView] setSomething:x]; //won't work
@@ -248,12 +242,11 @@ CPTableColumnUserResizingMask = 1 << 1;
*/
- (void)setDataView:(CPView)aView
{
if (_dataView === aView)
return;
if (_dataView)
_dataViewData[[_dataView UID]] = nil;
[aView setThemeState:CPThemeStateTableDataView];
_dataView = aView;
_dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView];
}
@@ -292,7 +285,10 @@ CPTableColumnUserResizingMask = 1 << 1;
// unarchive the data view cache
var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]];
newDataView.identifier = dataViewUID;
// make sure only we have control over the size and placement
[newDataView setAutoresizingMask:CPViewNotSizable];
return newDataView;
}
@@ -325,7 +321,7 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*
Returns YES if the user can edit cells associated with the receiver by double-clicking the
Returns YES if the user can edit cells associated with the receiver by double-clicking the
column in the NSTableView, NO otherwise.
*/
- (BOOL)isEditable
@@ -348,7 +344,14 @@ CPTableColumnUserResizingMask = 1 << 1;
- (void)setHidden:(BOOL)shouldBeHidden
{
shouldBeHidden = !!shouldBeHidden
if (_isHidden === shouldBeHidden)
return;
_isHidden = shouldBeHidden;
[[self headerView] setHidden:shouldBeHidden];
[[self tableView] _tableColumnVisibilityDidChange:self];
}
- (BOOL)isHidden
@@ -359,7 +362,7 @@ CPTableColumnUserResizingMask = 1 << 1;
//Setting Tool Tips
/*
Sets the tooltip string that is displayed when the cursor pauses over the
Sets the tooltip string that is displayed when the cursor pauses over the
header cell of the receiver.
*/
- (void)setHeaderToolTip:(CPString)aToolTip
@@ -382,13 +385,86 @@ CPTableColumnUserResizingMask = 1 << 1;
@end
@implementation CPTableColumn (Bindings)
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
{
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
if (![aBinding isEqual:@"someListOfExceptedBindings(notAcceptedBindings)"])
[[self tableView] _establishBindingsIfUnbound:anObject];
}
- (void)prepareDataView:(CPView)aDataView forRow:(unsigned)aRow
{
var bindingsDictionary = [CPKeyValueBinding allBindingsForObject:self],
keys = [bindingsDictionary allKeys];
for (var i = 0, count = [keys count]; i < count; i++)
{
var bindingName = keys[i],
bindingPath = [aDataView _replacementKeyPathForBinding:bindingName],
binding = [bindingsDictionary objectForKey:bindingName],
bindingInfo = binding._info,
destination = [bindingInfo objectForKey:CPObservedObjectKey],
keyPath = [bindingInfo objectForKey:CPObservedKeyPathKey],
dotIndex = keyPath.lastIndexOf("."),
value;
if (dotIndex === CPNotFound)
value = [[destination valueForKeyPath:keyPath] objectAtIndex:aRow];
else
{
/*
Optimize the prototypical use case where the key path describes a value
in an array. Without this optimization, we call CPArray's valueForKey
which generates as many values as objects in the array, of which we then
pick one and throw away the rest.
The optimization is to get the array and access the value directly. This
turns the operation into a single access regardless of how long the model
array is.
*/
var firstPart = keyPath.substring(0, dotIndex),
secondPart = keyPath.substring(dotIndex + 1),
firstValue = [destination valueForKeyPath:firstPart];
if ([firstValue isKindOfClass:CPArray])
value = [[firstValue objectAtIndex:aRow] valueForKeyPath:secondPart];
else
value = [[firstValue valueForKeyPath:secondPart] objectAtIndex:aRow];
}
value = [binding transformValue:value withOptions:[bindingInfo objectForKey:CPOptionsKey]];
// console.log(bindingName+" : "+keyPath+" : "+aRow+" : "+[[destination valueForKeyPath:keyPath] objectAtIndex:aRow]);
[aDataView setValue:value forKey:bindingPath];
}
}
//- (void)objectValue
//{
// return nil;
//}
- (void)setValue:(CPArray)content
{
[[self tableView] reloadData];
}
@end
var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
CPTableColumnHeaderViewKey = @"CPTableColumnHeaderViewKey",
CPTableColumnDataViewKey = @"CPTableColumnDataViewKey",
CPTableColumnWidthKey = @"CPTableColumnWidthKey",
CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey",
CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey",
CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey";
CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey",
CPTableColumnIsHiddenKey = @"CPTableColumnIsHiddenKey",
CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey",
CPTableColumnIsEditableKey = @"CPTableColumnIsEditableKey";
@implementation CPTableColumn (CPCoding)
@@ -409,7 +485,11 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
_resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
_resizingMask = [aCoder decodeIntForKey:CPTableColumnResizingMaskKey];
_isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenKey];
_isEditable = [aCoder decodeBoolForKey:CPTableColumnIsEditableKey];
_sortDescriptorPrototype = [aCoder decodeObjectForKey:CPSortDescriptorPrototypeKey];
}
return self;
@@ -427,6 +507,10 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
[aCoder encodeBool:_isHidden forKey:CPTableColumnIsHiddenKey];
[aCoder encodeBool:_isEditable forKey:CPTableColumnIsEditableKey];
[aCoder encodeObject:_sortDescriptorPrototype forKey:CPSortDescriptorPrototypeKey];
}
@end
@@ -463,4 +547,4 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
reason:@"dataCellForRow: is not supported. Use -dataViewForRow:row instead."];
}
@end
@end
+380 -196
View File
@@ -20,56 +20,64 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPIndexSet.j>
@import "CPTableColumn.j"
@import "CPTableView.j"
@import "CPView.j"
var CPThemeStatePressed = CPThemeState("pressed");
@implementation _CPTableColumnHeaderView : CPView
{
_CPImageAndTextView _textField;
_CPImageAndTextView _textField;
}
+ (CPString)defaultThemeClass
{
return @"columnHeader";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], CGSizeMakeZero()]
forKeys:[@"background-color", @"text-alignment", @"text-inset", @"text-color", @"text-font", @"text-shadow-color", @"text-shadow-offset"]];
}
- (void)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self _init];
}
return self;
}
- (void)_init
{
_textField = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(5, 1, CGRectGetWidth([self bounds]) - 10, CGRectGetHeight([self bounds]) - 1)];
_textField = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
[_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_textField setLineBreakMode:CPLineBreakByTruncatingTail];
[_textField setTextColor: [CPColor colorWithHexString: @"333333"]];
[_textField setFont:[CPFont boldSystemFontOfSize:12.0]];
[_textField setAlignment:CPLeftTextAlignment];
[_textField setVerticalAlignment:CPCenterVerticalTextAlignment];
[_textField setTextShadowColor:[CPColor whiteColor]];
[_textField setTextShadowOffset:CGSizeMake(0,1)];
[self addSubview:_textField];
}
- (void)layoutSubviews
{
var themeState = [self themeState];
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
if(themeState & CPThemeStateHighlighted && themeState & CPThemeStatePressed)
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted-pressed.png", CGSizeMake(1.0, 22.0))]];
else if (themeState & CPThemeStateHighlighted)
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted.png", CGSizeMake(1.0, 22.0))]];
else if (themeState & CPThemeStatePressed)
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-pressed.png", CGSizeMake(1.0, 22.0))]];
else
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
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 setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
[_textField setFont:[self currentValueForThemeAttribute:@"text-font"]];
[_textField setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]];
[_textField setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
[_textField setAlignment:[self currentValueForThemeAttribute:@"text-alignment"]];
}
- (void)setStringValue:(CPString)string
@@ -97,11 +105,6 @@ var CPThemeStatePressed = CPThemeState("pressed");
[_textField setFont:aFont];
}
- (void)setValue:(id)aValue forThemeAttribute:(id)aKey
{
[_textField setValue:aValue forThemeAttribute:aKey];
}
- (void)_setIndicatorImage:(CPImage)anImage
{
if (anImage)
@@ -139,7 +142,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:[_textField text] forKey:_CPTableColumnHeaderViewStringValueKey];
[aCoder encodeObject:[_textField image] forKey:_CPTableColumnHeaderViewImageKey];
[aCoder encodeObject:[_textField font] forKey:_CPTableColumnHeaderViewFontKey];
@@ -149,27 +152,47 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
@implementation CPTableHeaderView : CPView
{
int _resizedColumn @accessors(readonly, property=resizedColumn);
int _draggedColumn @accessors(readonly, property=draggedColumn);
int _pressedColumn @accessors(readonly, property=pressedColumn);
float _draggedDistance @accessors(readonly, property=draggedDistance);
float _lastLocation;
float _columnOldWidth;
CPTableView _tableView @accessors(property=tableView);
CGPoint _mouseDownLocation;
CGPoint _previousTrackingLocation;
int _activeColumn;
int _pressedColumn;
BOOL _isResizing;
BOOL _isDragging;
BOOL _isTrackingColumn;
BOOL _drawsColumnLines;
float _columnOldWidth;
CPTableView _tableView @accessors(property=tableView);
}
+ (CPString)defaultThemeClass
{
return @"tableHeaderRow";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPColor grayColor]]
forKeys:[@"background-color", @"divider-color"]];
}
- (void)_init
{
_resizedColumn = -1;
_draggedColumn = -1;
_mouseDownLocation = _CGPointMakeZero();
_previousTrackingLocation = _CGPointMakeZero();
_activeColumn = -1;
_pressedColumn = -1;
_draggedDistance = 0.0;
_lastLocation = nil;
_columnOldWidth = nil;
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
_isResizing = NO;
_isDragging = NO;
_isTrackingColumn = NO;
_drawsColumnLines = YES;
_columnOldWidth = 0.0;
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
}
- (id)initWithFrame:(CGRect)aFrame
@@ -184,39 +207,41 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
- (int)columnAtPoint:(CGPoint)aPoint
{
return [_tableView columnAtPoint:CGPointMake(aPoint.x, 0)];
return [_tableView columnAtPoint:CGPointMake(aPoint.x, aPoint.y)];
}
- (CGRect)headerRectOfColumn:(int)aColumnIndex
{
var tableColumns = [_tableView tableColumns];
var headerRect = [self bounds],
columnRect = [_tableView rectOfColumn:aColumnIndex];
if (aColumnIndex < 0 || aColumnIndex > [tableColumns count])
[CPException raise:"invalid" reason:"tried to get headerRectOfColumn: on invalid column"];
headerRect.origin.x = _CGRectGetMinX(columnRect);
headerRect.size.width = _CGRectGetWidth(columnRect);
// UPDATE COLUMN RANGES ?
var tableRange = _tableView._tableColumnRanges[aColumnIndex],
bounds = [self bounds];
return headerRect;
}
var rMinX = ROUND(tableRange.location);
bounds.origin.x = rMinX;
bounds.size.width = FLOOR(tableRange.length + tableRange.location - rMinX);
return bounds;
- (void)setDrawsColumnLines:(BOOL)aFlag
{
_drawsColumnLines = aFlag;
}
- (BOOL)drawsColumnLines
{
return _drawsColumnLines;
}
- (CGRect)_cursorRectForColumn:(int)column
{
if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask))
return CGRectMakeZero();
return _CGRectMakeZero();
var rect = [self headerRectOfColumn:column];
rect.origin.x = CGRectGetMaxX(rect) - 5;
rect.origin.x = _CGRectGetMaxX(rect) - 5;
rect.size.width = 20;
return rect;
return rect;
}
- (void)_setPressedColumn:(CPInteger)column
@@ -224,118 +249,294 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
if (_pressedColumn != -1)
{
var headerView = [_tableView._tableColumns[_pressedColumn] headerView];
[headerView unsetThemeState:CPThemeStatePressed];
}
[headerView unsetThemeState:CPThemeStateHighlighted];
}
if (column != -1)
{
var headerView = [_tableView._tableColumns[column] headerView];
[headerView setThemeState:CPThemeStatePressed];
[headerView setThemeState:CPThemeStateHighlighted];
}
_pressedColumn = column;
}
- (void)mouseDown:(CPEvent)theEvent
{
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
clickedColumn = [self columnAtPoint:mouseLocation];
// should we send column -1 ?
[_tableView _sendDelegateDidMouseDownInHeader:clickedColumn];
var resizeLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
resizedColumn = [self columnAtPoint:resizeLocation];
if (resizedColumn == -1)
return;
// 2 different tracking methods: one for resizing/stop-resizing, another one for selection/reordering
if ([_tableView allowsColumnResizing]
&& CGRectContainsPoint([self _cursorRectForColumn:resizedColumn], mouseLocation))
{
_resizedColumn = resizedColumn;
[_tableView._tableColumns[_resizedColumn] setDisableResizingPosting:YES];
[_tableView setDisableAutomaticResizing:YES];
[self trackResizeWithEvent:theEvent];
}
else
{
[self _setPressedColumn:clickedColumn];
[self trackMouseWithEvent:theEvent];
}
[self trackMouse:theEvent];
}
- (void)trackMouseWithEvent:(CPEvent)theEvent
- (void)trackMouse:(CPEvent)theEvent
{
var type = [theEvent type];
if (type == CPLeftMouseUp)
{
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
clickedColumn = [self columnAtPoint:location];
var type = [theEvent type],
currentLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil];
[self _setPressedColumn:-1];
if (clickedColumn != -1)
[_tableView _didClickTableColumn:clickedColumn modifierFlags:[theEvent modifierFlags]];
return;
}
// Take the right columns resize tracking area into account
currentLocation.x -= 5.0;
[CPApp setTarget:self selector:@selector(trackMouseWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPLeftMouseDownMask untilDate:nil inMode:nil dequeue:YES];
}
- (void)trackResizeWithEvent:(CPEvent)anEvent
{
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
tableColumn = [[_tableView tableColumns] objectAtIndex:_resizedColumn],
type = [anEvent type];
if (_lastLocation == nil)
_lastLocation = location;
if (_columnOldWidth == nil)
_columnOldWidth = [tableColumn width];
var columnIndex = [self columnAtPoint:currentLocation],
shouldResize = [self shouldResizeTableColumn:columnIndex at:_CGPointMake(currentLocation.x + 5.0, currentLocation.y)];
if (type === CPLeftMouseUp)
{
[self _updateResizeCursor:anEvent];
[tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth];
[tableColumn setDisableResizingPosting:NO];
[_tableView setDisableAutomaticResizing:NO];
_resizedColumn = -1;
_lastLocation = nil;
_columnOldWidth = nil;
return;
}
else if (type === CPLeftMouseDragged)
{
var newWidth = [tableColumn width] + location.x - _lastLocation.x;
if (newWidth < [tableColumn minWidth])
[[CPCursor resizeRightCursor] set];
else if (newWidth > [tableColumn maxWidth])
[[CPCursor resizeLeftCursor] set];
if (shouldResize)
[self stopResizingTableColumn:_activeColumn at:currentLocation];
else if ([self _shouldStopTrackingTableColumn:columnIndex at:currentLocation])
{
[_tableView _didClickTableColumn:columnIndex modifierFlags:[theEvent modifierFlags]];
[self stopTrackingTableColumn:columnIndex at:currentLocation];
_isTrackingColumn = NO;
}
[self _updateResizeCursor:[CPApp currentEvent]];
_activeColumn = CPNotFound;
return;
}
if (type === CPLeftMouseDown)
{
if (columnIndex === -1)
return;
_mouseDownLocation = currentLocation;
_activeColumn = columnIndex;
[_tableView _sendDelegateDidMouseDownInHeader:columnIndex];
if (shouldResize)
[self startResizingTableColumn:columnIndex at:currentLocation];
else
{
_tableView._lastColumnShouldSnap = NO;
[tableColumn setWidth:newWidth];
// FIXME: there has to be a better way to do this...
// We should refactor the auto resizing crap.
// We need to figure out the exact cocoa behavior here though.
_lastLocation = location;
[self startTrackingTableColumn:columnIndex at:currentLocation];
_isTrackingColumn = YES;
}
}
else if (type === CPLeftMouseDragged)
{
if (shouldResize)
[self continueResizingTableColumn:_activeColumn at:currentLocation];
else
{
if (_activeColumn === columnIndex && _CGRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation))
{
if (_isTrackingColumn && _pressedColumn !== -1)
{
if (![self continueTrackingTableColumn:columnIndex at:currentLocation])
return; // Stop tracking the column, because it's being dragged
} else
[self startTrackingTableColumn:columnIndex at:currentLocation];
[[CPCursor resizeLeftRightCursor] set];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
} else if (_isTrackingColumn && _pressedColumn !== -1)
[self stopTrackingTableColumn:_activeColumn at:currentLocation];
}
}
[CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
_previousTrackingLocation = currentLocation;
[CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
- (void)startTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
[self _setPressedColumn:aColumnIndex];
}
- (BOOL)continueTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
if ([self _shouldDragTableColumn:aColumnIndex at:aPoint])
{
var columnRect = [self headerRectOfColumn:aColumnIndex],
offset = _CGPointMakeZero(),
view = [_tableView _dragViewForColumn:aColumnIndex event:[CPApp currentEvent] offset:offset],
viewLocation = _CGPointMakeZero();
viewLocation.x = ( _CGRectGetMinX(columnRect) + offset.x ) + ( aPoint.x - _mouseDownLocation.x );
viewLocation.y = _CGRectGetMinY(columnRect) + offset.y;
[self dragView:view at:viewLocation offset:_CGSizeMakeZero() event:[CPApp currentEvent]
pasteboard:[CPPasteboard pasteboardWithName:CPDragPboard] source:self slideBack:YES];
return NO;
}
return YES;
}
- (BOOL)_shouldStopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
return _isTrackingColumn && _activeColumn === aColumnIndex &&
_CGRectContainsPoint([self headerRectOfColumn:aColumnIndex], aPoint);
}
- (void)stopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
[self _setPressedColumn:CPNotFound];
[self _updateResizeCursor:[CPApp currentEvent]];
}
- (BOOL)_shouldDragTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
return [_tableView allowsColumnReordering] && ABS(aPoint.x - _mouseDownLocation.x) >= 10.0;
}
- (CGRect)_headerRectOfLastVisibleColumn
{
var tableColumns = [_tableView tableColumns],
columnIndex = [tableColumns count];
while (columnIndex--)
{
var tableColumn = [tableColumns objectAtIndex:columnIndex];
if (![tableColumn isHidden])
return [self headerRectOfColumn:columnIndex];
}
return nil;
}
- (void)_constrainDragView:(CPView)theDragView at:(CGPoint)aPoint
{
var tableColumns = [_tableView tableColumns],
lastColumnRect = [self _headerRectOfLastVisibleColumn],
activeColumnRect = [self headerRectOfColumn:_activeColumn],
dragWindow = [theDragView window],
frame = [dragWindow frame];
// Convert the frame origin from the global coordinate system to the windows' coordinate system
frame.origin = [[self window] convertGlobalToBase:frame.origin];
// the from the window to the view
frame.origin = [self convertPoint:frame.origin fromView:nil];
// This effectively clamps the value between the minimum and maximum
frame.origin.x = MAX(0.0, MIN(_CGRectGetMinX(frame), _CGRectGetMaxX(lastColumnRect) - _CGRectGetWidth(activeColumnRect)));
// Make sure the column cannot move vertically
frame.origin.y = _CGRectGetMinY(lastColumnRect);
// Convert the calculated origin back to the window coordinate system
frame.origin = [self convertPoint:frame.origin toView:nil];
// Then back to the global coordinate system
frame.origin = [[self window] convertBaseToGlobal:frame.origin];
[dragWindow setFrame:frame];
}
- (void)_moveColumn:(int)aFromIndex toColumn:(int)aToIndex
{
[_tableView moveColumn:aFromIndex toColumn:aToIndex];
_activeColumn = aToIndex;
_pressedColumn = _activeColumn;
}
- (void)draggedView:(CPView)aView beganAt:(CGPoint)aPoint
{
_isDragging = YES;
var column = [[_tableView tableColumns] objectAtIndex:_activeColumn];
[[column headerView] setHidden:YES];
[_tableView _setDraggedColumn:column];
[self setNeedsDisplay:YES];
}
- (void)draggedView:(CPView)aView movedTo:(CGPoint)aPoint
{
[self _constrainDragView:aView at:aPoint];
var dragWindow = [aView window],
dragWindowFrame = [dragWindow frame];
var hoverPoint = CGPointCreateCopy(aPoint);
if (aPoint.x < _previousTrackingLocation.x)
hoverPoint = _CGPointMake(_CGRectGetMinX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame));
else if (aPoint.x > _previousTrackingLocation.x)
hoverPoint = _CGPointMake(_CGRectGetMaxX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame));
// Convert the hover point from the global coordinate system to windows' coordinate system
hoverPoint = [[self window] convertGlobalToBase:hoverPoint];
// then to the view
hoverPoint = [self convertPoint:hoverPoint fromView:nil];
var hoveredColumn = [self columnAtPoint:hoverPoint];
if (hoveredColumn !== -1)
{
var columnRect = [self headerRectOfColumn:hoveredColumn],
columnCenterPoint = [self convertPoint:CGPointMake(_CGRectGetMidX(columnRect), _CGRectGetMidY(columnRect)) fromView:self];
if (hoveredColumn < _activeColumn && hoverPoint.x < columnCenterPoint.x)
[self _moveColumn:_activeColumn toColumn:hoveredColumn];
else if (hoveredColumn > _activeColumn && hoverPoint.x > columnCenterPoint.x)
[self _moveColumn:_activeColumn toColumn:hoveredColumn];
}
_previousTrackingLocation = aPoint;
}
- (void)draggedView:(CPImage)aView endedAt:(CGPoint)aLocation operation:(CPDragOperation)anOperation
{
_isDragging = NO;
_isTrackingColumn = NO; // We need to do this explicitly because the mouse up section of trackMouse is never reached
[_tableView _setDraggedColumn:nil];
[[[[_tableView tableColumns] objectAtIndex:_activeColumn] headerView] setHidden:NO];
[self stopTrackingTableColumn:_activeColumn at:aLocation];
[self setNeedsDisplay:YES];
}
- (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
if (_isResizing)
return YES;
if (_isTrackingColumn)
return NO;
return [_tableView allowsColumnResizing] && _CGRectContainsPoint([self _cursorRectForColumn:aColumnIndex], aPoint);
}
- (void)startResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
_isResizing = YES;
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex];
[tableColumn setDisableResizingPosting:YES];
[_tableView setDisableAutomaticResizing:YES];
}
- (void)continueResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex],
newWidth = [tableColumn width] + aPoint.x - _previousTrackingLocation.x;
if (newWidth < [tableColumn minWidth])
[[CPCursor resizeRightCursor] set];
else if (newWidth > [tableColumn maxWidth])
[[CPCursor resizeLeftCursor] set];
else
{
_tableView._lastColumnShouldSnap = NO;
[tableColumn setWidth:newWidth];
[[CPCursor resizeLeftRightCursor] set];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
}
- (void)stopResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex];
[tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth];
[tableColumn setDisableResizingPosting:NO];
[_tableView setDisableAutomaticResizing:NO];
_isResizing = NO;
}
- (void)_updateResizeCursor:(CPEvent)theEvent
@@ -347,15 +548,15 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
return;
}
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
mouseOverLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
overColumn = [self columnAtPoint:mouseOverLocation];
if (overColumn >= 0 && CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation))
if (overColumn >= 0 && _CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation))
{
var tableColumn = [[_tableView tableColumns] objectAtIndex:overColumn],
width = [tableColumn width];
if (width == [tableColumn minWidth])
[[CPCursor resizeRightCursor] set];
else if (width == [tableColumn maxWidth])
@@ -367,14 +568,8 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
[[CPCursor arrowCursor] set];
}
- (void)viewDidMoveToWindow
{
//if ([_tableView allowsColumnResizing])
// [[self window] setAcceptsMouseMovedEvents:YES];
}
- (void)mouseEntered:(CPEvent)theEvent
{
{
[self _updateResizeCursor:theEvent];
}
@@ -392,31 +587,33 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
- (void)layoutSubviews
{
var tableColumns = [_tableView tableColumns],
count = [tableColumns count];
for (var i = 0; i < count; i++)
count = [tableColumns count];
for (var i = 0; i < count; i++)
{
var column = [tableColumns objectAtIndex:i],
headerView = [column headerView];
var frame = [self headerRectOfColumn:i];
frame.size.height -= 0.5;
if (i > 0)
if (i > 0)
{
frame.origin.x += 0.5;
frame.size.width -= 1;
}
[headerView setFrame:frame];
if([headerView superview] != self)
[self addSubview:headerView];
}
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
}
- (void)drawRect:(CGRect)aRect
{
if (!_tableView)
if (!_tableView || ![self drawsColumnLines])
return;
var context = [[CPGraphicsContext currentContext] graphicsPort],
@@ -428,55 +625,41 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1);
CGContextSetLineWidth(context, 1);
CGContextSetStrokeColor(context, [_tableView gridColor]);
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"divider-color"]);
[exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange];
var columnArrayIndex = 0,
columnArrayCount = columnsArray.length,
columnMaxX;
CGContextBeginPath(context);
for(; columnArrayIndex < columnArrayCount; columnArrayIndex++)
{
// grab each column rect and add vertical lines
var columnIndex = columnsArray[columnArrayIndex],
columnToStroke = [self headerRectOfColumn:columnIndex];
columnMaxX = CGRectGetMaxX(columnToStroke);
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMinY(columnToStroke)));
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMaxY(columnToStroke)));
columnMaxX = _CGRectGetMaxX(columnToStroke);
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMaxY(columnToStroke)));
}
CGContextClosePath(context);
CGContextStrokePath(context);
/*
var maxY = CGRectGetMaxY([self bounds]);
// draw normal gradient for remaining space
if (supportsCanvasGradient)
/*if (_isDragging)
{
aRect.origin.x = columnMaxX - 0.5;
aRect.size.width -= columnMaxX;
CGContextBeginPath(context);
CGContextAddRect(context, CGRectMake(columnMaxX + 1, 0, CGRectGetMaxX([self bounds]) - columnMaxX, CGRectGetHeight([self bounds])));
CGContextClosePath(context);
CGContextDrawLinearGradient(context, [_CPTableColumnHeaderView headerGradient], CGPointMake(0,0), CGPointMake(0, maxY - 1),0);
}
// Draw bottom line
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0, maxY - 0.5);
CGContextAddLineToPoint(context, CGRectGetMaxX([self bounds]), maxY - 0.5);
CGContextClosePath(context);
CGContextStrokePath(context);
*/
CGContextSetFillColor(context, [CPColor grayColor]);
CGContextFillRect(context, [self headerRectOfColumn:_activeColumn])
}*/
}
@end
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey",
CPTableHeaderViewDrawsColumnLines = @"CPTableHeaderViewDrawsColumnLines";
@implementation CPTableHeaderView (CPCoding)
@@ -486,6 +669,7 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
{
[self _init];
_tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey];
_drawsColumnLines = [aCoder decodeBoolForKey:CPTableHeaderViewDrawsColumnLines];
}
return self;
@@ -495,7 +679,7 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey];
[aCoder encodeBool:_drawsColumnLines forKey:CPTableHeaderViewDrawsColumnLines];
}
@end
+1082 -590
View File
File diff suppressed because it is too large Load Diff
+30
View File
@@ -0,0 +1,30 @@
/*
* CPText.j
* AppKit
*
* Created by Alexander Ljungberg.
* Copyright 2010, WireLoad, LLC.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
CPEnterCharacter = "\u0003";
CPBackspaceCharacter = "\u0008";
CPTabCharacter = "\u0009";
CPNewlineCharacter = "\u000a";
CPFormFeedCharacter = "\u000c";
CPCarriageReturnCharacter = "\u000d";
CPBackTabCharacter = "\u0019";
CPDeleteCharacter = "\u007f";
+269 -122
View File
@@ -26,9 +26,6 @@
@import "CPCompatibility.j"
@import "_CPImageAndTextView.j"
#include "CoreGraphics/CGGeometry.h"
#include "Platform/Platform.h"
#include "Platform/DOM/CPDOMDisplayServer.h"
CPTextFieldSquareBezel = 0; /*! A textfield bezel with a squared corners. */
CPTextFieldRoundedBezel = 1; /*! A textfield bezel with rounded corners. */
@@ -49,7 +46,7 @@ var CPTextFieldDOMInputElement = nil,
CPTextFieldCachedSelectStartFunction = nil,
CPTextFieldCachedDragFunction = nil,
CPTextFieldBlurFunction = nil;
#endif
var CPSecureTextFieldCharacter = "\u2022";
@@ -80,15 +77,18 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
BOOL _isEditable;
BOOL _isSelectable;
BOOL _isSecure;
BOOL _willBecomeFirstResponderByClick;
BOOL _drawsBackground;
CPColor _textFieldBackgroundColor;
id _placeholderString;
id _originalPlaceholderString;
BOOL _currentValueIsPlaceholder;
id _delegate;
CPString _textDidChangeValue;
// NS-style Display Properties
@@ -155,7 +155,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return textField;
}
+ (CPString)themeClass
+ (CPString)defaultThemeClass
{
return "textfield";
}
@@ -199,7 +199,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
}
CPTextFieldHandleBlur = function(anEvent)
{
{
CPTextFieldInputOwner = nil;
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
@@ -207,10 +207,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
//FIXME make this not onblur
CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction;
CPTextFieldDOMStandardInputElement = CPTextFieldDOMInputElement;
}
if (CPFeatureIsCompatible(CPInputTypeCanBeChangedFeature))
{
if ([self isSecure])
@@ -237,14 +237,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurFunction;
}
CPTextFieldDOMInputElement = CPTextFieldDOMPasswordInputElement;
}
else
{
CPTextFieldDOMInputElement = CPTextFieldDOMStandardInputElement;
}
return CPTextFieldDOMInputElement;
}
#endif
@@ -262,18 +262,29 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"];
}
return self;
}
#pragma mark Controlling Editability and Selectability
/*!
Sets whether or not the receiver text field can be edited
/*!
Sets whether or not the receiver text field can be edited. If NO, any
ongoing edit is ended.
*/
- (void)setEditable:(BOOL)shouldBeEditable
{
if (_isEditable === shouldBeEditable)
return;
_isEditable = shouldBeEditable;
if (shouldBeEditable)
_isSelectable = YES;
// We only allow first responder status if the field is editable and enabled.
if (!shouldBeEditable && [[self window] firstResponder] === self)
[[self window] makeFirstResponder:nil];
}
/*!
@@ -284,6 +295,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return _isEditable;
}
/*!
Sets whether the field reacts to events. If NO, any ongoing edit is
ended.
*/
- (void)setEnabled:(BOOL)shouldBeEnabled
{
[super setEnabled:shouldBeEnabled];
// We only allow first responder status if the field is editable and enabled.
if (!shouldBeEnabled && [[self window] firstResponder] === self)
[[self window] makeFirstResponder:nil];
}
/*!
Sets whether the field's text is selectable by the user.
@param aFlag \c YES makes the text selectable
@@ -346,7 +370,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setBezelStyle:(CPTextFieldBezelStyle)aBezelStyle
{
var shouldBeRounded = aBezelStyle === CPTextFieldRoundedBezel;
if (shouldBeRounded)
[self setThemeState:CPTextFieldStateRounded];
else
@@ -392,9 +416,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
if (_drawsBackground == shouldDrawBackground)
return;
_drawsBackground = shouldDrawBackground;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
@@ -415,9 +439,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
if (_textFieldBackgroundColor == aColor)
return;
_textFieldBackgroundColor = aColor;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
@@ -480,24 +504,31 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
_DOMElement.appendChild(element);
window.setTimeout(function()
{
window.setTimeout(function()
{
element.focus();
// Select the text if the textfield became first responder through keyboard interaction
if (!_willBecomeFirstResponderByClick)
[self selectText:self];
_willBecomeFirstResponderByClick = NO;
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
CPTextFieldInputOwner = self;
}, 0.0);
element.value = [self stringValue];
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
CPTextFieldInputIsActive = YES;
if (document.attachEvent)
{
CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
[[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
[[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
}
@@ -519,14 +550,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var element = [self _inputElement];
[self setObjectValue:element.value];
if ([self stringValue] !== element.value)
[self _setStringValue:element.value];
CPTextFieldInputResigning = YES;
element.blur();
if (!CPTextFieldInputDidBlur)
CPTextFieldBlurFunction();
CPTextFieldInputDidBlur = NO;
CPTextFieldInputResigning = NO;
@@ -537,13 +569,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
if (document.attachEvent)
{
CPTextFieldCachedSelectStartFunction = nil;
CPTextFieldCachedDragFunction = nil;
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
CPTextFieldCachedSelectStartFunction = nil;
CPTextFieldCachedDragFunction = nil;
}
#endif
//post CPControlTextDidEndEditingNotification
@@ -573,21 +605,50 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
// Don't track! (ever?)
if ([self isEditable] && [self isEnabled])
return [[self window] makeFirstResponder:self];
{
_willBecomeFirstResponderByClick = YES;
[[self window] makeFirstResponder:self];
}
else if ([self isSelectable])
{
if (document.attachEvent)
{
CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
[[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
[[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
}
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
}
else
return [[self nextResponder] mouseDown:anEvent];
}
- (void)mouseUp:(CPEvent)anEvent
{
if (![self isEditable] || ![self isEnabled])
if (![self isSelectable] && (![self isEditable] || ![self isEnabled]))
[[self nextResponder] mouseUp:anEvent];
else if ([self isSelectable])
{
if (document.attachEvent)
{
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
CPTextFieldCachedSelectStartFunction = nil
CPTextFieldCachedDragFunction = nil;
}
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
}
}
- (void)mouseDragged:(CPEvent)anEvent
{
if (![self isEditable] || ![self isEnabled])
if (![self isSelectable] && (![self isEditable] || ![self isEnabled]))
[[self nextResponder] mouseDragged:anEvent];
else if ([self isSelectable])
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
}
- (void)keyUp:(CPEvent)anEvent
@@ -624,29 +685,16 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
}
else if ([anEvent keyCode] === CPTabKeyCode)
{
if ([anEvent modifierFlags] & CPShiftKeyMask)
[[self window] selectPreviousKeyView:self];
else
[[self window] selectNextKeyView:self];
if ([[[self window] firstResponder] respondsToSelector:@selector(selectText:)])
[[[self window] firstResponder] selectText:self];
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
}
else
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
- (void)textDidBlur:(CPNotification)note
{
//this looks to prevent false propagation of notifications for other objects
if([note object] != self)
// this looks to prevent false propagation of notifications for other objects
if ([note object] != self)
return;
[[CPNotificationCenter defaultCenter] postNotification:note];
@@ -654,13 +702,22 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)textDidFocus:(CPNotification)note
{
//this looks to prevent false propagation of notifications for other objects
if([note object] != self)
// this looks to prevent false propagation of notifications for other objects
if ([note object] != self)
return;
[[CPNotificationCenter defaultCenter] postNotification:note];
}
- (void)sendAction:(SEL)anAction to:(id)anObject
{
// Don't reverse set our empty value
if (!_currentValueIsPlaceholder)
[self _reverseSetBinding];
[CPApp sendAction:anAction to:anObject from:self];
}
/*!
Returns the string the text field.
*/
@@ -683,7 +740,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setObjectValue:(id)aValue
{
[super setObjectValue:aValue];
#if PLATFORM(DOM)
if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self)
@@ -707,11 +764,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
Sets a placeholder string for the receiver. The placeholder is displayed until editing begins,
and after editing ends, if the text field has an empty string value
*/
-(void)setPlaceholderString:(CPString)aStringValue
- (void)setPlaceholderString:(CPString)aStringValue
{
if (_placeholderString === aStringValue)
return;
_placeholderString = aStringValue;
// Only update things if we need to show the placeholder
@@ -730,43 +787,101 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return _placeholderString;
}
- (void)_setCurrentValueIsPlaceholder:(BOOL)isPlaceholder
{
// The initial _currentValueIsPlaceholder is null so convert it to NO for comparison purposes.
if (!!_currentValueIsPlaceholder === isPlaceholder)
return;
if (isPlaceholder)
{
// Save the original placeholder value so we can restore it later
// Only do this if the placeholder is not already overridden because the bindings logic might call this method
// several times and we don't want the bindings placeholder to ever become the original placeholder
if (!_currentValueIsPlaceholder)
_originalPlaceholderString = [self placeholderString];
// Set the current string value as the current placeholder and clear the string value
[self setPlaceholderString:[self stringValue]];
[self setStringValue:@""];
}
else
{
// Restore the original placeholder, the actual textfield value is already correct
// because it was set using setValue:forKey:
[self setPlaceholderString:_originalPlaceholderString];
}
_currentValueIsPlaceholder = isPlaceholder;
}
/*!
Size to fit has two behavior, depending on if the receiver is an editable text field or not.
For non-editable text fields (typically, a label), sizeToFit will change the frame of the
receiver to perfectly fit the current text in stringValue in the current font, and respecting
the current theme values for content-inset, min-size, and max-size.
For editable text fields, sizeToFit will ONLY change the HEIGHT of the text field. It will not
change the width of the text field. You can use setFrameSize: with the current height to set the
width, and you can get the size of a string with [CPString sizeWithFont:].
For non-bezeled text fields (typically a label), sizeToFit has two behaviors, depending
on the line break mode of the receiver.
For non-bezeled receivers with a non-wrapping line break mode, sizeToFit will change the frame of the
receiver to perfectly fit the current text in stringValue in the current font, respecting
the current theme value for content-inset. For receivers with a wrapping line break mode,
sizeToFit will wrap the text within the current width (respecting the current content-inset),
so it will ONLY change the HEIGHT.
For bezeled text fields (typically editable fields), sizeToFit will ONLY change the HEIGHT
of the text field. It will not change the width of the text field. sizeToFit will attempt to
change the height to fit a single line of text, respecting the current theme values for min-size,
max-size and content-inset.
The logic behind this decision is that most of the time you do not know what content will be placed
in an editable text field, so you want to just choose a fixed width and leave it at that size.
in a bezeled text field, so you want to just choose a fixed width and leave it at that size.
However, since you don't know how tall it needs to be if you change the font, sizeToFit will still be
useful for making the textfield an appropriate height.
*/
- (void)sizeToFit
{
var size = [([self stringValue] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]],
[self setFrameSize:[self _minimumFrameSize]];
}
- (CGSize)_minimumFrameSize
{
var frameSize = [self frameSize],
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
minSize = [self currentValueForThemeAttribute:@"min-size"],
maxSize = [self currentValueForThemeAttribute:@"max-size"];
maxSize = [self currentValueForThemeAttribute:@"max-size"],
lineBreakMode = [self lineBreakMode],
text = ([self stringValue] || @" "),
textSize = _CGSizeMakeCopy(frameSize),
font = [self currentValueForThemeAttribute:@"font"];
size.width = MAX(size.width + contentInset.left + contentInset.right, minSize.width);
size.height = MAX(size.height + contentInset.top + contentInset.bottom, minSize.height);
textSize.width -= contentInset.left + contentInset.right;
textSize.height -= contentInset.top + contentInset.bottom;
if (maxSize.width >= 0.0)
size.width = MIN(size.width, maxSize.width);
if (frameSize.width !== 0 &&
![self isBezeled] &&
(lineBreakMode === CPLineBreakByWordWrapping || lineBreakMode === CPLineBreakByCharWrapping))
{
textSize = [text sizeWithFont:font inWidth:textSize.width];
}
else
textSize = [text sizeWithFont:font];
if (maxSize.height >= 0.0)
size.height = MIN(size.height, maxSize.height);
frameSize.height = textSize.height + contentInset.top + contentInset.bottom;
if ([self isEditable])
size.width = CGRectGetWidth([self frame]);
if ([self isBezeled])
{
frameSize.height = MAX(frameSize.height, minSize.height);
[self setFrameSize:size];
if (maxSize.width > 0.0)
frameSize.width = MIN(frameSize.width, maxSize.width);
if (maxSize.height > 0.0)
frameSize.height = MIN(frameSize.height, maxSize.height);
}
else
frameSize.width = textSize.width + contentInset.left + contentInset.right;
frameSize.width = MAX(frameSize.width, minSize.width);
return frameSize;
}
/*!
@@ -776,16 +891,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
#if PLATFORM(DOM)
var element = [self _inputElement];
if (([self isEditable] || [self isSelectable]))
{
if ([[self window] firstResponder] === self)
window.setTimeout(function() { element.select(); }, 0);
else
{
[[self window] makeFirstResponder:self];
else if ([self window] !== nil && [[self window] makeFirstResponder:self])
window.setTimeout(function() {[self selectText:sender];}, 0);
}
}
#endif
}
@@ -813,7 +925,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
if (![CPPlatform isBrowser])
{
[self copy:sender];
[self deleteBackwards:sender];
[self deleteBackward:sender];
}
}
@@ -826,7 +938,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
if (![[pasteboard types] containsObject:CPStringPboardType])
return;
[self deleteBackwards:sender];
[self deleteBackward:sender];
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
@@ -834,7 +946,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
[self setStringValue:newValue];
[self setSelectedRange:CPMakeRange(selectedRange.location+pasteString.length, 0)];
[self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)];
}
}
@@ -844,14 +956,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return CPMakeRange(0, 0);
// we wrap this in try catch because firefox will throw an exception in certain instances
try
try
{
var inputElement = [self _inputElement],
selectionStart = inputElement.selectionStart,
selectionEnd = inputElement.selectionEnd;
if ([selectionStart isKindOfClass:CPNumber])
return CPMakeRange(selectionStart, selectionEnd - selectionStart);
return CPMakeRange(selectionStart, selectionEnd - selectionStart);
// browsers which don't support selectionStart/selectionEnd (aka IE).
var theDocument = inputElement.ownerDocument || inputElement.document,
@@ -863,8 +975,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
range.setEndPoint('EndToStart', selectionRange);
return CPMakeRange(range.text.length, selectionRange.text.length);
}
}
catch (e)
}
catch (e)
{
// fall through to the return
}
@@ -879,7 +991,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var inputElement = [self _inputElement];
try
try
{
if ([inputElement.selectionStart isKindOfClass:CPNumber])
{
@@ -892,7 +1004,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var theDocument = inputElement.ownerDocument || inputElement.document,
existingRange = theDocument.selection.createRange(),
range = inputElement.createTextRange();
if (range.inRange(existingRange))
{
range.collapse(true);
@@ -912,7 +1024,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self selectText:sender];
}
- (void)deleteBackwards:(id)sender
- (void)deleteBackward:(id)sender
{
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
@@ -927,7 +1039,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setDelegate:(id)aDelegate
{
var defaultCenter = [CPNotificationCenter defaultCenter];
//unsubscribe the existing delegate if it exists
if (_delegate)
{
@@ -937,24 +1049,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[defaultCenter removeObserver:_delegate name:CPTextFieldDidFocusNotification object:self];
[defaultCenter removeObserver:_delegate name:CPTextFieldDidBlurNotification object:self];
}
_delegate = aDelegate;
if ([_delegate respondsToSelector:@selector(controlTextDidBeginEditing:)])
[defaultCenter
addObserver:_delegate
selector:@selector(controlTextDidBeginEditing:)
name:CPControlTextDidBeginEditingNotification
object:self];
if ([_delegate respondsToSelector:@selector(controlTextDidChange:)])
[defaultCenter
addObserver:_delegate
selector:@selector(controlTextDidChange:)
name:CPControlTextDidChangeNotification
object:self];
if ([_delegate respondsToSelector:@selector(controlTextDidEndEditing:)])
[defaultCenter
addObserver:_delegate
@@ -985,30 +1097,30 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (CGRect)contentRectForBounds:(CGRect)bounds
{
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
if (!contentInset)
return bounds;
bounds.origin.x += contentInset.left;
bounds.origin.y += contentInset.top;
bounds.size.width -= contentInset.left + contentInset.right;
bounds.size.height -= contentInset.top + contentInset.bottom;
return bounds;
}
- (CGRect)bezelRectForBounds:(CFRect)bounds
- (CGRect)bezelRectForBounds:(CGRect)bounds
{
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
if (_CGInsetIsEmpty(bezelInset))
return bounds;
bounds.origin.x += bezelInset.left;
bounds.origin.y += bezelInset.top;
bounds.size.width -= bezelInset.left + bezelInset.right;
bounds.size.height -= bezelInset.top + bezelInset.bottom;
return bounds;
}
@@ -1016,10 +1128,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
if (aName === "bezel-view")
return [self bezelRectForBounds:[self bounds]];
else if (aName === "content-view")
return [self contentRectForBounds:[self bounds]];
return [super rectForEphemeralSubviewNamed:aName];
}
@@ -1030,19 +1142,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO];
return view;
}
else
{
var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
//[view setImagePosition:CPNoImage];
[view setHitTests:NO];
return view;
}
return [super createEphemeralSubviewNamed:aName];
}
@@ -1051,10 +1163,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:@"content-view"];
if (bezelView)
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"bezel-view"];
@@ -1064,7 +1176,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[contentView setHidden:[self hasThemeState:CPThemeStateEditing]];
var string = "";
if ([self hasThemeState:CPTextFieldStatePlaceholder])
string = [self placeholderString];
else
@@ -1087,6 +1199,22 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
}
}
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
var count = objects.length,
value = [objects[0] valueForKeyPath:aKeyPath];
[self setStringValue:value];
[self setPlaceholderString:@""];
while (count-- > 1)
if (value !== [objects[count] valueForKeyPath:aKeyPath])
{
[self setPlaceholderString:@"Multiple Values"];
[self setStringValue:@""];
}
}
@end
var secureStringForString = function(aString)
@@ -1095,7 +1223,7 @@ var secureStringForString = function(aString)
if (!aString)
return "";
return Array(aString.length+1).join(CPSecureTextFieldCharacter);
return Array(aString.length + 1).join(CPSecureTextFieldCharacter);
}
@@ -1106,6 +1234,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
CPTextFieldBezelStyleKey = "CPTextFieldBezelStyleKey",
CPTextFieldDrawsBackgroundKey = "CPTextFieldDrawsBackgroundKey",
CPTextFieldLineBreakModeKey = "CPTextFieldLineBreakModeKey",
CPTextFieldAlignmentKey = "CPTextFieldAlignmentKey",
CPTextFieldBackgroundColorKey = "CPTextFieldBackgroundColorKey",
CPTextFieldPlaceholderStringKey = "CPTextFieldPlaceholderStringKey";
@@ -1119,7 +1248,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
[self setEditable:[aCoder decodeBoolForKey:CPTextFieldIsEditableKey]];
@@ -1129,9 +1258,24 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
[self setTextFieldBackgroundColor:[aCoder decodeObjectForKey:CPTextFieldBackgroundColorKey]];
[self setLineBreakMode:[aCoder decodeIntForKey:CPTextFieldLineBreakModeKey]];
[self setAlignment:[aCoder decodeIntForKey:CPTextFieldAlignmentKey]];
[self setPlaceholderString:[aCoder decodeObjectForKey:CPTextFieldPlaceholderStringKey]];
// Make sure the frame is big enough
var minSize = [self _minimumFrameSize];
minSize.width = MAX(CGRectGetWidth([self frame]), minSize.width);
minSize.height = MAX(CGRectGetHeight([self frame]), minSize.height);
// Only size multiline bezeled textfields if it's to small to fit the content
if ([self isBezeled])
if ([self lineBreakMode] === CPLineBreakByCharWrapping || [self lineBreakMode] == CPLineBreakByWordWrapping)
minSize.height = MAX(CGRectGetHeight([self frame]), minSize.height);
[self setFrameSize:minSize];
}
return self;
}
@@ -1142,14 +1286,17 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeBool:_isEditable forKey:CPTextFieldIsEditableKey];
[aCoder encodeBool:_isSelectable forKey:CPTextFieldIsSelectableKey];
[aCoder encodeBool:_drawsBackground forKey:CPTextFieldDrawsBackgroundKey];
[aCoder encodeObject:_textFieldBackgroundColor forKey:CPTextFieldBackgroundColorKey];
[aCoder encodeInt:[self lineBreakMode] forKey:CPTextFieldLineBreakModeKey];
[aCoder encodeInt:[self alignment] forKey:CPTextFieldAlignmentKey];
[aCoder encodeObject:_placeholderString forKey:CPTextFieldPlaceholderStringKey];
}
+188 -20
View File
@@ -24,8 +24,10 @@
@import <Foundation/CPString.j>
@import <Foundation/CPKeyedUnarchiver.j>
var CPThemesByName = { },
CPThemeDefaultTheme = nil;
var CPThemesByName = { },
CPThemeDefaultTheme = nil,
CPThemeDefaultHudTheme = nil;
/*!
@@ -48,6 +50,27 @@ var CPThemesByName = { },
return CPThemeDefaultTheme;
}
/*!
Set the default HUD theme. If set to nil, the default described in defaultHudTheme
will be used.
*/
+ (void)setDefaultHudTheme:(CPTheme)aTheme
{
CPThemeDefaultHudTheme = aTheme;
}
/*!
The default HUD theme is (sometimes) used for windows with the CPHUDBackgroundWindowMask
style mask. The default is theme with the name of the default theme with -HUD appended
at the end.
*/
+ (CPTheme)defaultHudTheme
{
if (!CPThemeDefaultHudTheme)
CPThemeDefaultHudTheme = [CPTheme themeNamed:[[self defaultTheme] name] + "-HUD"];
return CPThemeDefaultHudTheme;
}
+ (CPTheme)themeNamed:(CPString)aName
{
return CPThemesByName[aName];
@@ -73,9 +96,110 @@ var CPThemesByName = { },
return _name;
}
- (_CPThemeAttribute)_attributeWithName:(CPString)aName forClass:(CPString)aClass
/*!
Returns an array of names of themed classes defined in this theme, as found in its
ThemeDescriptors.j file.
NOTE: The names are not class names (such as "CPButton"), but the names returned
by the class' +defaultThemeClass method. For example, the name for CPCheckBox is "check-box",
as defined in CPCheckBox::themeClass.
*/
- (CPArray)classNames
{
var attributes = [_attributes objectForKey:aClass];
return [_attributes allKeys];
}
/*!
Returns a dictionary of all theme attributes defined for the given class, as found in the
theme's ThemeDescriptors.j file. The keys of the dictionary are attribute names, and the values
are instances of _CPThemeAttribute.
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
@param aClass The themed class whose attributes you want to retrieve
@return A dictionary of attributes or nil
*/
- (CPDictionary)attributesForClass:(id)aClass
{
if (!aClass)
return nil;
var className = nil;
if ([aClass isKindOfClass:[CPString class]])
{
// See if it is a class name
var theClass = CPClassFromString(aClass);
if (theClass)
aClass = theClass;
else
className = aClass;
}
if (!className)
{
if ([aClass isKindOfClass:[CPView class]])
{
if ([aClass respondsToSelector:@selector(defaultThemeClass)])
className = [aClass defaultThemeClass];
else if ([aClass respondsToSelector:@selector(themeClass)])
{
CPLog.warn(@"%@ themeClass is deprecated in favor of defaultThemeClass",CPStringFromClass([anObject class]));
className = [aClass themeClass];
}
else
return nil;
}
else
[CPException raise:CPInvalidArgumentException reason:@"aClass must be a class object or a string."];
}
return [_attributes objectForKey:className];
}
/*!
Returns an array of names of all theme attributes defined for the given class, as found in the
theme's ThemeDescriptors.j file.
The \c aClass parameter can be one of the following:
- A class instance, for example the result of [CPCheckBox class]. The class must be a subclass
of CPView.
- A class name, for example "CPCheckBox".
- A themed class name, for example "check-box".
If \c aClass does not refer to a themed class in this theme, nil is returned.
@param aClass The themed class whose attributes you want to retrieve
@return An array of attribute names or nil
*/
- (CPDictionary)attributeNamesForClass:(id)aClass
{
var attributes = [self attributesForClass:aClass];
if (attributes)
return [attributes allKeys];
else
return [CPArray array];
}
/*!
Returns a theme attribute defined for the given class, as found in the
theme's ThemeDescriptors.j file.
\c aName should be the attribute name as you would pass to the method
CPView::valueForThemeAttribute:.
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
@param aName The name of the attribute you want to retrieve
@param aClass The themed class in which to look for the attribute
@return An instance of _CPThemeAttribute or nil
*/
- (_CPThemeAttribute)attributeWithName:(CPString)aName forClass:(id)aClass
{
var attributes = [self attributesForClass:aClass];
if (!attributes)
return nil;
@@ -83,12 +207,53 @@ var CPThemesByName = { },
return [attributes objectForKey:aName];
}
/*!
Returns the value for a theme attribute in its normal state, as defined for the given class
in the theme's ThemeDescriptors.j file.
\c aName should be the attribute name as you would pass to the method
CPView::valueForThemeAttribute:.
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
@param aName The name of the attribute whose value you want to retrieve
@param aClass The themed class in which to look for the attribute
@return A value or nil
*/
- (id)valueForAttributeWithName:(CPString)aName forClass:(id)aClass
{
return [self valueForAttributeWithName:aName inState:CPThemeStateNormal forClass:aClass];
}
/*!
Returns the value for a theme attribute in a given state, as defined for the given class
in the theme's ThemeDescriptors.j file. This is the equivalent of the method
CPView::valueForThemeAttribute:inState:, but retrieves the value from the theme definition as
opposed to a single view's current theme state.
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
@param aName The name of the attribute whose value you want to retrieve
@param aState The state qualifier for the attribute
@param aClass The themed class in which to look for the attribute
@return A value or nil
*/
- (id)valueForAttributeWithName:(CPString)aName inState:(CPThemeState)aState forClass:(id)aClass
{
var attribute = [self attributeWithName:aName forClass:aClass];
if (!attribute)
return nil;
return [attribute valueForState:aState];
}
- (void)takeThemeFromObject:(id)anObject
{
var attributes = [anObject _themeAttributeDictionary],
attributeName = nil,
attributeNames = [attributes keyEnumerator],
objectThemeClass = [[anObject class] themeClass];
objectThemeClass = [anObject themeClass];
while (attributeName = [attributeNames nextObject])
[self _recordAttribute:[attributes objectForKey:attributeName] forClass:objectThemeClass];
@@ -242,6 +407,9 @@ CPThemeStateNormal = CPThemeStates["normal"] = 0;
CPThemeStateDisabled = CPThemeState("disabled");
CPThemeStateHighlighted = CPThemeState("highlighted");
CPThemeStateSelected = CPThemeState("selected");
CPThemeStateTableDataView = CPThemeState("tableDataView");
CPThemeStateSelectedDataView = CPThemeStateSelectedTableDataView = CPThemeState("selectedTableDataView");
CPThemeStateGroupRow = CPThemeState("CPThemeStateGroupRow");
CPThemeStateBezeled = CPThemeState("bezeled");
CPThemeStateBordered = CPThemeState("bordered");
CPThemeStateEditable = CPThemeState("editable");
@@ -254,10 +422,10 @@ CPThemeStateCircular = CPThemeState("circular");
{
CPString _name;
id _defaultValue;
CPDictionary _values;
CPDictionary _values @accessors(readonly, getter=values);
JSObject _cache;
CPThemeAttribute _parentAttribute;
_CPThemeAttribute _parentAttribute;
}
- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue
@@ -378,7 +546,7 @@ CPThemeStateCircular = CPThemeState("circular");
return value;
}
- (void)setParentAttribute:(CPThemeAttribute)anAttribute
- (void)setParentAttribute:(_CPThemeAttribute)anAttribute
{
if (_parentAttribute === anAttribute)
return;
@@ -387,7 +555,7 @@ CPThemeStateCircular = CPThemeState("circular");
_parentAttribute = anAttribute;
}
- (CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
- (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
{
var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue];
@@ -472,15 +640,15 @@ CPThemeStateCircular = CPThemeState("circular");
@end
var cachedNumberOfOnes = [ 0 /*000000*/, 1 /*000001*/, 1 /*000010*/, 2 /*000011*/, 1 /*000100*/, 2 /*000101*/, 2 /*000110*/,
3 /*000111*/, 1 /*001000*/, 2 /*001001*/, 2 /*001010*/, 3 /*001011*/, 2 /*001100*/, 3 /*001101*/,
3 /*001110*/, 4 /*001111*/, 1 /*010000*/, 2 /*010001*/, 2 /*010010*/, 3 /*010011*/, 2 /*010100*/,
3 /*010101*/, 3 /*010110*/, 4 /*010111*/, 2 /*011000*/, 3 /*011001*/, 3 /*011010*/, 4 /*011011*/,
3 /*011100*/, 4 /*011101*/, 4 /*011110*/, 5 /*011111*/, 1 /*100000*/, 2 /*100001*/, 2 /*100010*/,
3 /*100011*/, 2 /*100100*/, 3 /*100101*/, 3 /*100110*/, 4 /*100111*/, 2 /*101000*/, 3 /*101001*/,
3 /*101010*/, 4 /*101011*/, 3 /*101100*/, 4 /*101101*/, 4 /*101110*/, 5 /*101111*/, 2 /*110000*/,
3 /*110001*/, 3 /*110010*/, 4 /*110011*/, 3 /*110100*/, 4 /*110101*/, 4 /*110110*/, 5 /*110111*/,
3 /*111000*/, 4 /*111001*/, 4 /*111010*/, 5 /*111011*/, 4 /*111100*/, 5 /*111101*/, 5 /*111110*/,
var cachedNumberOfOnes = [ 0 /*000000*/, 1 /*000001*/, 1 /*000010*/, 2 /*000011*/, 1 /*000100*/, 2 /*000101*/, 2 /*000110*/,
3 /*000111*/, 1 /*001000*/, 2 /*001001*/, 2 /*001010*/, 3 /*001011*/, 2 /*001100*/, 3 /*001101*/,
3 /*001110*/, 4 /*001111*/, 1 /*010000*/, 2 /*010001*/, 2 /*010010*/, 3 /*010011*/, 2 /*010100*/,
3 /*010101*/, 3 /*010110*/, 4 /*010111*/, 2 /*011000*/, 3 /*011001*/, 3 /*011010*/, 4 /*011011*/,
3 /*011100*/, 4 /*011101*/, 4 /*011110*/, 5 /*011111*/, 1 /*100000*/, 2 /*100001*/, 2 /*100010*/,
3 /*100011*/, 2 /*100100*/, 3 /*100101*/, 3 /*100110*/, 4 /*100111*/, 2 /*101000*/, 3 /*101001*/,
3 /*101010*/, 4 /*101011*/, 3 /*101100*/, 4 /*101101*/, 4 /*101110*/, 5 /*101111*/, 2 /*110000*/,
3 /*110001*/, 3 /*110010*/, 4 /*110011*/, 3 /*110100*/, 4 /*110101*/, 4 /*110110*/, 5 /*110111*/,
3 /*111000*/, 4 /*111001*/, 4 /*111010*/, 5 /*111011*/, 4 /*111100*/, 5 /*111101*/, 5 /*111110*/,
6 /*111111*/ ];
var numberOfOnes = function(aNumber)
@@ -551,7 +719,7 @@ function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme,
}
if (aTheme && aClass)
[attribute setParentAttribute:[aTheme _attributeWithName:anAttributeName forClass:aClass]];
[attribute setParentAttribute:[aTheme attributeWithName:anAttributeName forClass:aClass]];
return attribute;
}
@@ -585,4 +753,4 @@ for (i = 0;i < Math.pow(2,6);++i)
}
print(str+']');
*/
*/
+34 -10
View File
@@ -22,9 +22,10 @@
@import <Foundation/CPObject.j>
@import <AppKit/CPTheme.j>
@import <AppKit/_CPCibCustomResource.j>
@import <AppKit/_CPCibKeyedUnarchiver.j>
@import "CPTheme.j"
@import "_CPCibCustomResource.j"
@import "_CPCibKeyedUnarchiver.j"
/*!
@ingroup appkit
@@ -33,37 +34,60 @@
@implementation CPThemeBlend : CPObject
{
CPBundle _bundle;
CPArray _themes @accessors(readonly, getter=themes);
CPArray _themes;
id _loadDelegate;
}
- (id)initWithContentsOfURL:(CPURL)aURL
{
self = [super init];
if (self)
{
_bundle = [[CPBundle alloc] initWithPath:aURL];
}
return self;
}
/*!
Returns an array of names of the keyed theme archives that make up this blend.
Each item in the array will have the extension ".keyedtheme".
*/
- (CPArray)themes
{
return _themes;
}
/*!
Returns an array of names of the themes that make up this blend.
*/
- (CPArray)themeNames
{
var names = [];
for (var i = 0; i < _themes.length; ++i)
names.push(_themes[i].substring(0, _themes[i].indexOf(".keyedtheme")));
return names;
}
- (void)loadWithDelegate:(id)aDelegate
{
_loadDelegate = aDelegate;
[_bundle loadWithDelegate:self];
}
- (void)bundleDidFinishLoading:(CPBundle)aBundle
{
var themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"],
count = themes.length;
_themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"];
var count = _themes.length;
while (count--)
{
var path = [aBundle pathForResource:themes[count]],
var path = [aBundle pathForResource:_themes[count]],
unarchiver = [[_CPThemeKeyedUnarchiver alloc]
initForReadingWithData:[[CPURL URLWithString:path] staticResourceData]
bundle:_bundle];
+1250
View File
File diff suppressed because it is too large Load Diff
+21 -10
View File
@@ -28,8 +28,6 @@
@import "CPPopUpButton.j"
@import "CPToolbarItem.j"
#include "CoreGraphics/CGGeometry.h"
/*
@global
@@ -329,7 +327,11 @@ var CPToolbarConfigurationsByIdentifier = nil;
return _itemsSortedByVisibilityPriority;
}
- (void)validateVisibleToolbarItems
/*!
Validates the visible toolbar items by sending a validate message to
each visible toolbar item.
*/
- (void)validateVisibleItems
{
var toolbarItems = [self visibleItems],
count = [toolbarItems count];
@@ -466,7 +468,14 @@ var CPToolbarIdentifierKey = @"CPToolbarIdentifierKey",
// specified, it will be read later and the resulting call to -setDelegate:
// will cause -_reloadToolbarItems] to run again :-(
// FIXME: Can we make this better?
[self _reloadToolbarItems];
// Do this at the end of the run loop to allow all the cib-stuff to
// finish (establishing connections, etc.).
[[CPRunLoop currentRunLoop]
performSelector:@selector(_reloadToolbarItems)
target:self
argument:nil
order:0 modes:[CPDefaultRunLoopMode]];
}
return self;
@@ -559,6 +568,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
[_additionalItemsButton setImagePosition:CPImageOnly];
[[_additionalItemsButton menu] setShowsStateColumn:NO];
[[_additionalItemsButton menu] setAutoenablesItems:NO];
[_additionalItemsButton setAlternateImage:_CPToolbarViewExtraItemsAlternateImage];
}
@@ -789,14 +799,13 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
hasNonSeparatorItem = YES;
[_additionalItemsButton addItemWithTitle:[item label]];
var menuItem = [_additionalItemsButton itemArray][index + 1];
var menuItem = [[CPMenuItem alloc] initWithTitle:[item label] action:[item action] keyEquivalent:nil];
[menuItem setImage:[item image]];
[menuItem setTarget:[item target]];
[menuItem setAction:[item action]];
[menuItem setEnabled:[item isEnabled]];
[_additionalItemsButton addItem:menuItem];
}
}
else
@@ -970,7 +979,7 @@ var TOP_MARGIN = 5.0,
{
_imageView = [[CPImageView alloc] initWithFrame:[self bounds]];
[_imageView setImageScaling:CPScaleNone];
[_imageView setImageScaling:CPScaleProportionally];
[self addSubview:_imageView];
}
@@ -1051,6 +1060,8 @@ var TOP_MARGIN = 5.0,
[_imageView setAlphaValue:0.5];
[_labelField setAlphaValue:0.5];
}
[_toolbar tile];
}
- (CPColor)FIXME_labelColor
+6 -6
View File
@@ -23,8 +23,9 @@
@import <Foundation/CPObject.j>
@import <Foundation/CPString.j>
@import <AppKit/CPImage.j>
@import <AppKit/CPView.j>
@import "CPImage.j"
@import "CPView.j"
CPToolbarItemVisibilityPriorityStandard = 0;
CPToolbarItemVisibilityPriorityLow = -1000;
@@ -449,6 +450,9 @@ CPToolbarItemVisibilityPriorityUser
- (void)validate
{
var action = [self action],
target = [self target];
// View items do not do any target-action analysis.
if (_view)
{
@@ -458,13 +462,9 @@ CPToolbarItemVisibilityPriorityUser
return;
}
var action = [self action];
if (!action)
return [self setEnabled:NO];
var target = [self target];
if (target && ![target respondsToSelector:action])
return [self setEnabled:NO];
+197
View File
@@ -87,6 +87,40 @@
[_childNodes[count] sortWithSortDescriptors:sortDescriptors recursively:YES];
}
- (CPEnumerator)preOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorPreOrder];
}
- (CPEnumerator)inOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorInOrder];
}
- (CPEnumerator)postOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorPostOrder];
}
- (CPEnumerator)levelOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorLevelOrder];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
if (aState.state !== 0)
return 0;
// FIXME: Change this to inorder when implemented?
var count = [[self preOrder] countByEnumeratingWithState:aState objects:objects count:aCount];
// Dangerous?
aState.state = YES;
return count;
}
@end
var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
@@ -117,3 +151,166 @@ var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
}
@end
var _CPTreeNodeEnumeratorPreOrder = 0,
_CPTreeNodeEnumeratorInOrder = 1,
_CPTreeNodeEnumeratorPostOrder = 2,
_CPTreeNodeEnumeratorLevelOrder = 3;
@implementation _CPTreeNodeEnumerator : CPEnumerator
{
int _order;
Object _state;
CPTreeNode _treeNode;
}
+ (_CPTreeNodeEnumerator)enumeratorWithTreeNode:(CPTreeNode)aTreeNode order:(int)anOrder
{
return [[self alloc] initWithTreeNode:aTreeNode order:anOrder];
}
- (id)initWithTreeNode:(CPTreeNode)aTreeNode order:(int)anOrder
{
self = [super init];
if (self)
{
_order = anOrder
_state = [self _newState];
_treeNode = aTreeNode;
}
return self;
}
- (id)_newState
{
return { stack:[_treeNode], visited:[CPSet set] };
}
- (id)_preOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
var stack = state.stack;
if (stack.length <= 0)
return nil;
if (shouldReturnAllObjects)
var allObjects = [];
while (stack.length)
{
var currentNode = stack.pop(),
childNodes = currentNode._childNodes,
count = childNodes.length;
while (count--)
stack.push(childNodes[count]);
if (shouldReturnAllObjects)
allObjects.push(currentNode);
else
return currentNode;
}
return allObjects;
}
- (id)_inOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
// Implement.
}
- (id)_postOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
var stack = state.stack;
if (stack.length <= 0)
return nil;
var visited = state.visited;
if (shouldReturnAllObjects)
var allObjects = [];
while (stack.length)
{
var currentNode = [stack lastObject],
childNodes = currentNode._childNodes,
originalCount = stack.length,
count = childNodes.length;
while (count--)
{
var treeNode = childNodes[count];
if ([visited containsObject:treeNode])
continue;
else
stack.push(treeNode);
}
if (originalCount === stack.length)
{
[visited addObject:currentNode];
if (shouldReturnAllObjects)
allObjects.push(stack.pop());
else
return stack.pop();
}
}
return allObjects;
}
- (id)_levelOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
// Implement.
}
- (id)nextObject
{
if (_order === _CPTreeNodeEnumeratorPreOrder)
return [self _preOrderFromState:[self _newState] allObjects:NO];
else if (_order === _CPTreeNodeEnumeratorInOrder)
return [self _inOrderFromState:[self _newState] allObjects:NO];
else if (_order === _CPTreeNodeEnumeratorPostOrder)
return [self _postOrderFromState:[self _newState] allObjects:NO];
//else if (_order === _CPTreeNodeEnumeratorLevelOrder)
return [self _levelOrderFromState:[self _newState] allObjects:NO];
}
- (CPArray)allObjects
{
if (_order === _CPTreeNodeEnumeratorPreOrder)
return [self _preOrderFromState:[self _newState] allObjects:YES];
else if (_order === _CPTreeNodeEnumeratorInOrder)
return [self _inOrderFromState:[self _newState] allObjects:YES];
else if (_order === _CPTreeNodeEnumeratorPostOrder)
return [self _postOrderFromState:[self _newState] allObjects:YES];
//else if (_order === _CPTreeNodeEnumeratorLevelOrder)
return [self _levelOrderFromState:[self _newState] allObjects:NO];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
if (aState.state !== 0)
return 0;
var count = [[self allObjects] countByEnumeratingWithState:aState objects:objects count:aCount];
// Dangerous?
aState.state = YES;
return count;
}
@end
+396 -240
View File
File diff suppressed because it is too large Load Diff
+13 -12
View File
@@ -1,5 +1,5 @@
/*
* CPFlashView.j
* CPViewAnimation.j
* AppKit
*
* Created by Klaas Pieter Annema on September 3, 2009.
@@ -20,7 +20,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <AppKit/CPAnimation.j>
@import "CPAnimation.j"
CPViewAnimationTargetKey = @"CPViewAnimationTarget";
CPViewAnimationStartFrameKey = @"CPViewAnimationStartFrame";
@@ -69,7 +70,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
[super startAnimation];
}
- (void)setCurrentProgress:(NSAnimationProgress)progress
- (void)setCurrentProgress:(CPAnimationProgress)progress
{
[super setCurrentProgress:progress];
@@ -77,17 +78,17 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
while (animationIndex--)
{
var dictionary = [_viewAnimations objectAtIndex:animationIndex],
view = [self _targetView:dictionary]
startFrame = [self _startFrame:dictionary]
endFrame = [self _endFrame:dictionary]
differenceFrame = CPRectMakeZero();
view = [self _targetView:dictionary],
startFrame = [self _startFrame:dictionary],
endFrame = [self _endFrame:dictionary],
differenceFrame = _CGRectMakeZero();
differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x;
differenceFrame.origin.y = endFrame.origin.y - startFrame.origin.y;
differenceFrame.size.width = endFrame.size.width - startFrame.size.width;
differenceFrame.size.height = endFrame.size.height - startFrame.size.height;
var intermediateFrame = CPRectMakeZero();
var intermediateFrame = _CGRectMakeZero();
intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * progress;
intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * progress;
intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * progress;
@@ -103,7 +104,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress];
if (progress === 1.0)
[view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0];
[view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
}
}
@@ -124,7 +125,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
else if (effect === CPViewAnimationFadeOutEffect)
[view setAlphaValue:0.0];
[view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0];
[view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
}
[super stopAnimation];
@@ -139,7 +140,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
return targetView;
}
- (CPRect)_startFrame:(CPDictionary)dictionary
- (CGRect)_startFrame:(CPDictionary)dictionary
{
var startFrame = [dictionary valueForKey:CPViewAnimationStartFrameKey];
if (!startFrame)
@@ -148,7 +149,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
return startFrame;
}
- (CPRect)_endFrame:(CPDictionary)dictionary
- (CGRect)_endFrame:(CPDictionary)dictionary
{
var endFrame = [dictionary valueForKey:CPViewAnimationEndFrameKey];
if (!endFrame)
+24 -7
View File
@@ -20,7 +20,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <AppKit/CPResponder.j>
@import <Foundation/CPArray.j>
@import "CPApplication.j"
@import "CPCib.j"
@import "CPResponder.j"
var CPViewControllerCachedCibs;
@@ -47,7 +52,8 @@ var CPViewControllerCachedCibs;
*/
@implementation CPViewController : CPResponder
{
CPView _view;
CPView _view @accessors(property=view);
BOOL _isLoading;
id _representedObject @accessors(property=representedObject);
CPString _title @accessors(property=title);
@@ -99,6 +105,8 @@ var CPViewControllerCachedCibs;
_cibName = aCibNameOrNil;
_cibBundle = aCibBundleOrNil || [CPBundle mainBundle];
_cibExternalNameTable = anExternalNameTable || [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
_isLoading = NO;
}
return self;
@@ -111,16 +119,16 @@ var CPViewControllerCachedCibs;
If you create your views manually, you must override this method and use it to create your view and assign it to the view property.
The default implementation for programmatic views is to create a plain view. You can invoke super to utilize this view.
If you use Interface Builder to create your views and initialize the view controllerŃthat is, you initialize the view using the
initWithCibName:bundle: methodŃthen you must not override this method. The consequences risk shattering the space-time continuum.
If you use Interface Builder to create your views, you initialize the view using the
initWithCibName:bundle: method then you must not override this method. The consequences risk shattering the space-time continuum.
Note: The cib loading system is currently asynchronous.
Note: The cib loading system is currently synchronous.
*/
- (void)loadView
{
if (_view)
return;
// check if a cib is already cached for the current _cibName
var cib = [CPViewControllerCachedCibs objectForKey:_cibName];
@@ -143,6 +151,8 @@ var CPViewControllerCachedCibs;
{
if (!_view)
{
_isLoading = YES;
var cibOwner = [_cibExternalNameTable objectForKey:CPCibOwner];
if ([cibOwner respondsToSelector:@selector(viewControllerWillLoadCib:)])
@@ -163,6 +173,7 @@ var CPViewControllerCachedCibs;
if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)])
[cibOwner viewControllerDidLoadCib:self];
_isLoading = NO;
[self viewDidLoad];
}
@@ -173,7 +184,7 @@ var CPViewControllerCachedCibs;
/*!
This method is called after the view controller has loaded its associated views into memory.
This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method.
This method is most commonly used to perform additional initialization steps on views that are loaded from nib files.
This method is most commonly used to perform additional initialization steps on views that are loaded from cib files.
*/
- (void)viewDidLoad
{
@@ -189,7 +200,13 @@ var CPViewControllerCachedCibs;
*/
- (void)setView:(CPView)aView
{
var viewWasLoaded = !_view;
_view = aView;
// Make sure the viewDidLoad method is called if the view is set directly
if (!_isLoading && viewWasLoaded)
[self viewDidLoad];
}
@end
+100 -56
View File
@@ -20,9 +20,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <AppKit/CPView.j>
#include "Platform/Platform.h"
@import "CPView.j"
@import "CPScrollView.j"
// FIXME: implement these where possible:
@@ -50,30 +49,32 @@ CPWebViewScrollNative = 2;
{
CPScrollView _scrollView;
CPView _frameView;
IFrame _iframe;
CPString _mainFrameURL;
CPArray _backwardStack;
CPArray _forwardStack;
BOOL _ignoreLoadStart;
BOOL _ignoreLoadEnd;
id _downloadDelegate;
id _frameLoadDelegate;
id _policyDelegate;
id _resourceLoadDelegate;
id _UIDelegate;
CPWebScriptObject _wso;
CPString _url;
CPString _html;
Function _loadCallback;
int _scrollMode;
CGSize _scrollSize;
int _loadHTMLStringTimer;
}
- (id)initWithFrame:(CPRect)frameRect frameName:(CPString)frameName groupName:(CPString)groupName
@@ -93,10 +94,10 @@ CPWebViewScrollNative = 2;
_backwardStack = [];
_forwardStack = [];
_scrollMode = CPWebViewScrollNative;
[self _initDOMWithFrame:aFrame];
}
return self;
}
@@ -104,51 +105,52 @@ CPWebViewScrollNative = 2;
{
_ignoreLoadStart = YES;
_ignoreLoadEnd = YES;
_iframe = document.createElement("iframe");
_iframe.name = "iframe_" + Math.floor(Math.random()*10000);
_iframe.style.width = "100%";
_iframe.style.height = "100%";
_iframe.style.borderWidth = "0px";
_iframe.frameBorder = "0";
[self setDrawsBackground:YES];
_loadCallback = function() {
// HACK: this block handles the case where we don't know about loads initiated by the user clicking a link
if (!_ignoreLoadStart)
{
// post the start load notification
[self _startedLoading];
if (_mainFrameURL)
[_backwardStack addObject:_mainFrameURL];
// FIXME: this doesn't actually get the right URL for different domains. Not possible due to browser security restrictions.
_mainFrameURL = _iframe.src;
_mainFrameURL = _iframe.src;
// clear the forward
[_forwardStack removeAllObjects];
}
else
_ignoreLoadStart = NO;
if (!_ignoreLoadEnd)
{
[self _finishedLoading];
}
else
_ignoreLoadEnd = NO;
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
if (_iframe.addEventListener)
_iframe.addEventListener("load", _loadCallback, false);
else if (_iframe.attachEvent)
_iframe.attachEvent("onload", _loadCallback);
_frameView = [[CPView alloc] initWithFrame:[self bounds]];
[_frameView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
@@ -156,9 +158,9 @@ CPWebViewScrollNative = 2;
[_scrollView setAutohidesScrollers:YES];
[_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_scrollView setDocumentView:_frameView];
_frameView._DOMElement.appendChild(_iframe);
[self _setScrollMode:_scrollMode];
[self addSubview:_scrollView];
@@ -166,12 +168,37 @@ CPWebViewScrollNative = 2;
- (void)setFrameSize:(CPSize)aSize
{
{
[super setFrameSize:aSize];
[self _resizeWebFrame];
}
- (BOOL)_resizeWebFrame
- (void)_attachScrollEventIfNecessary
{
if (_scrollMode !== CPWebViewScrollAppKit)
return;
var win = null;
try { win = [self DOMWindow]; } catch (e) {}
if (win && win.addEventListener)
{
var scrollEventHandler = function(anEvent)
{
var frameBounds = [self bounds],
frameCenter = CGPointMake(CGRectGetMidX(frameBounds), CGRectGetMidY(frameBounds)),
windowOrigin = [self convertPoint:frameCenter toView:nil],
globalOrigin = [[self window] convertBaseToBridge:windowOrigin];
anEvent._overrideLocation = globalOrigin;
[[[self window] platformWindow] scrollEvent:anEvent];
};
win.addEventListener("DOMMouseScroll", scrollEventHandler, false);
}
}
- (void)_resizeWebFrame
{
if (_scrollMode === CPWebViewScrollAppKit)
{
@@ -181,13 +208,14 @@ CPWebViewScrollNative = 2;
}
else
{
[_frameView setFrameSize:[_scrollView contentSize]];
var visibleRect = [_frameView visibleRect];
[_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))];
// try to get the document size so we can correctly set the frame
var win = null;
try { win = [self DOMWindow]; } catch (e) {}
if (win && win.document)
if (win && win.document && win.document.body)
{
var width = win.document.body.scrollWidth,
height = win.document.body.scrollHeight;
@@ -200,9 +228,11 @@ CPWebViewScrollNative = 2;
else
{
CPLog.warn("using default size 800*1600");
[_frameView setFrameSize:CGSizeMake(800, 1600)];
}
[_frameView scrollRectToVisible:visibleRect];
}
}
}
@@ -211,14 +241,17 @@ CPWebViewScrollNative = 2;
{
if (_scrollMode == aScrollMode)
return;
[self _setScrollMode:aScrollMode];
}
- (void)_setScrollMode:(int)aScrollMode
{
_scrollMode = aScrollMode;
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
_scrollMode = CPWebViewScrollNative;
else
_scrollMode = aScrollMode;
_ignoreLoadStart = YES;
_ignoreLoadEnd = YES;
@@ -229,16 +262,16 @@ CPWebViewScrollNative = 2;
{
[_scrollView setHasHorizontalScroller:YES];
[_scrollView setHasVerticalScroller:YES];
_iframe.setAttribute("scrolling", "no");
}
else
{
[_scrollView setHasHorizontalScroller:NO];
[_scrollView setHasVerticalScroller:NO];
_iframe.setAttribute("scrolling", "auto");
[_frameView setFrameSize:[_scrollView bounds].size];
}
@@ -256,14 +289,16 @@ CPWebViewScrollNative = 2;
[self _setScrollMode:CPWebViewScrollAppKit];
[_frameView setFrameSize:[_scrollView contentSize]];
[self _startedLoading];
_ignoreLoadStart = YES;
_ignoreLoadEnd = NO;
_url = null;
_html = aString;
[self _load];
}
@@ -272,13 +307,13 @@ CPWebViewScrollNative = 2;
[self _setScrollMode:CPWebViewScrollNative];
[self _startedLoading];
_ignoreLoadStart = YES;
_ignoreLoadEnd = NO;
_url = _mainFrameURL;
_html = null;
[self _load];
}
@@ -293,11 +328,19 @@ CPWebViewScrollNative = 2;
// clear the iframe
_iframe.src = "";
// need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document
window.setTimeout(function() {
if (_loadHTMLStringTimer !== nil)
{
window.clearTimeout(_loadHTMLStringTimer);
_loadHTMLStringTimer = nil;
}
// need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document
_loadHTMLStringTimer = window.setTimeout(function()
{
var win = [self DOMWindow];
win.document.write(_html);
if (win)
win.document.write(_html);
window.setTimeout(_loadCallback, 1);
}, 0);
@@ -315,7 +358,8 @@ CPWebViewScrollNative = 2;
- (void)_finishedLoading
{
[self _resizeWebFrame];
[self _attachScrollEventIfNecessary];
[[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressFinishedNotification object:self];
if ([_frameLoadDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)])
@@ -328,7 +372,7 @@ CPWebViewScrollNative = 2;
}
- (void)setMainFrameURL:(CPString)URLString
{
{
if (_mainFrameURL)
[_backwardStack addObject:_mainFrameURL];
_mainFrameURL = URLString;
@@ -345,9 +389,9 @@ CPWebViewScrollNative = 2;
[_forwardStack addObject:_mainFrameURL];
_mainFrameURL = [_backwardStack lastObject];
[_backwardStack removeLastObject];
[self _loadMainFrameURL];
return YES;
}
return NO;
@@ -361,9 +405,9 @@ CPWebViewScrollNative = 2;
[_backwardStack addObject:_mainFrameURL];
_mainFrameURL = [_forwardStack lastObject];
[_forwardStack removeLastObject];
[self _loadMainFrameURL];
return YES;
}
return NO;
@@ -586,7 +630,7 @@ CPWebViewScrollNative = 2;
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
// FIXME: encode/decode these?
@@ -594,14 +638,14 @@ CPWebViewScrollNative = 2;
_backwardStack = [];
_forwardStack = [];
_scrollMode = CPWebViewScrollNative;
#if PLATFORM(DOM)
[self _initDOMWithFrame:[self frame]];
#endif
[self setBackgroundColor:[CPColor whiteColor]];
}
return self;
}
+354 -150
View File
File diff suppressed because it is too large Load Diff
@@ -71,11 +71,12 @@ var _CPToolbarViewBackgroundColor = nil;
[self addSubview:_toolbarBackgroundView positioned:CPWindowBelow relativeTo:nil];
}
var frame = CGRectMakeZero();
frame.origin = CGPointMakeCopy([self toolbarOffset]);
var frame = CGRectMakeZero(),
toolbarOffset = [self toolbarOffset];
frame.origin = CGPointMake(toolbarOffset.width, toolbarOffset.height);
frame.size = [_toolbarView frame].size;
[_toolbarBackgroundView setFrame:frame];
}
+12 -12
View File
@@ -43,21 +43,21 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
_CPHUDWindowViewBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground0.png"] size:CPSizeMake(6.0, 78.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground1.png"] size:CPSizeMake(1.0, 78.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(6.0, 78.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground0.png"] size:CPSizeMake(7.0, 37.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground1.png"] size:CPSizeMake(1.0, 37.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(7.0, 37.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(6.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(5.0, 5.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(6.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(7.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(2.0, 2.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(7.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(6.0, 6.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground7.png"] size:CPSizeMake(6.0, 6.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground8.png"] size:CPSizeMake(6.0, 6.0)]
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(7.0, 3.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground7.png"] size:CPSizeMake(1.0, 3.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground8.png"] size:CPSizeMake(7.0, 3.0)]
]]];
_CPHUDWindowViewCloseImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowClose.png"] size:CPSizeMake(20.0, 20.0)];
_CPHUDWindowViewCloseActiveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowCloseActive.png"] size:CPSizeMake(20.0, 20.0)];
_CPHUDWindowViewCloseImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowClose.png"] size:CPSizeMake(18.0, 18.0)];
_CPHUDWindowViewCloseActiveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowCloseActive.png"] size:CPSizeMake(18.0, 18.0)];
}
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
@@ -148,7 +148,7 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
{
var closeSize = [_CPHUDWindowViewCloseImage size];
_closeButton = [[CPButton alloc] initWithFrame:CGRectMake(4.0, 4.0, closeSize.width, closeSize.height)];
_closeButton = [[CPButton alloc] initWithFrame:CGRectMake(8.0, 5.0, closeSize.width, closeSize.height)];
[_closeButton setBordered:NO];
+1
View File
@@ -22,6 +22,7 @@
@import "_CPWindowView.j"
var GRADIENT_HEIGHT = 41.0;
var _CPTexturedWindowHeadGradientColor = nil,
+5 -6
View File
@@ -20,10 +20,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPView.j"
@import "CPImageView.j"
#include "../CoreGraphics/CGGeometry.h"
@import "CPView.j"
var _CPWindowViewResizeIndicatorImage = nil;
@@ -36,6 +34,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
CGSize _resizeIndicatorOffset;
CPView _toolbarView;
CGSize _toolbarOffset;
// BOOL _isAnimatingToolbar;
@@ -80,8 +79,8 @@ var _CPWindowViewResizeIndicatorImage = nil;
if (self)
{
_styleMask = aStyleMask;
_resizeIndicatorOffset = CGSizeMake(0.0, 0.0);
_toolbarOffset = CGSizeMake(0.0, 0.0);
_resizeIndicatorOffset = CGSizeMakeZero();
_toolbarOffset = CGSizeMakeZero();
}
return self;
@@ -269,7 +268,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
- (CGSize)toolbarOffset
{
return CGSizeMakeZero();
return _toolbarOffset;
}
- (CPColor)toolbarLabelColor
+2 -23
View File
@@ -27,8 +27,6 @@
@import "CPWindow.j"
@import "CPDocument.j"
#include "Platform/Platform.h"
/*!
@ingroup appkit
@@ -133,7 +131,7 @@
if (_window)
return;
[[CPBundle bundleForClass:[_cibOwner class]] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]];
[[CPBundle mainBundle] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]];
}
/*!
@@ -322,25 +320,6 @@
return _documents;
}
- (void)setViewController:(CPViewController)aViewController
{
var containerView = [self viewControllerContainerView] || [[self window] contentView],
view = [_viewController view],
frame = view ? [view frame] : [containerView bounds];
[view removeFromSuperview];
_viewController = aViewController;
view = [_viewController view];
if (view)
{
[view setFrame:frame];
[containerView addSubview:view];
}
}
- (void)setViewControllerContainerView:(CPView)aView
{
_viewControllerContainerView = aView;
@@ -443,7 +422,7 @@
if (_windowCibPath)
return _windowCibPath;
return [[CPBundle bundleForClass:[_cibOwner class]] pathForResource:_windowCibName + @".cib"];
return [[CPBundle mainBundle] pathForResource:_windowCibName + @".cib"];
}
// Setting and Getting Window Attributes
+7 -2
View File
@@ -150,7 +150,7 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
var topLevelObjects = [anExternalNameTable objectForKey:CPCibTopLevelObjects];
[objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects]
[objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects];
[objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects];
[objectData awakeWithOwner:owner topLevelObjects:topLevelObjects];
@@ -171,12 +171,17 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)data
{
// FIXME: Why aren't we getting connection:didFailWithError:
if (!data)
return [self connection:aConnection didFailWithError:nil];
_data = [CPData dataWithRawString:data];
}
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
{
alert("cib: connection failed.");
if ([_loadDelegate respondsToSelector:@selector(cibDidFailToLoad:)])
[_loadDelegate cibDidFailToLoad:self];
_loadDelegate = nil;
}
+9 -3
View File
@@ -39,9 +39,11 @@
// Not having a selector is a fatal error.
if (!selector)
{
[CPException
raise:CPInvalidArgumentException
reason:@"-[" + [self className] + ' ' + _cmd + @"] selector " + selectorName + @" does not exist."];
}
// If the destination doesn't respond to this selector, warn but don't die.
if (_destination && ![_destination respondsToSelector:selector])
@@ -58,7 +60,7 @@
else
[CPException
raise:CPInvalidArgumentException
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + " does not respond to setAction:"];
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + @" does not respond to setAction:"];
// Not being able to set the target is a fatal error.
if ([_source respondsToSelector:@selector(setTarget:)])
@@ -67,10 +69,14 @@
else
[CPException
raise:CPInvalidArgumentException
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + " does not respond to setTarget:"];
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + @" does not respond to setTarget:"];
}
@end
@implementation _CPCibControlConnector : CPCibControlConnector { } @end
@implementation _CPCibControlConnector : CPCibControlConnector
{
}
@end
+19 -14
View File
@@ -37,12 +37,12 @@ var CPCibOwner = @"CPCibOwner";
@implementation CPBundle (CPCibLoading)
+ (void)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable
+ (CPCib)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable
{
[[[CPCib alloc] initWithContentsOfURL:anAbsolutePath] instantiateCibWithExternalNameTable:aNameTable];
return [[[CPCib alloc] initWithContentsOfURL:anAbsolutePath] instantiateCibWithExternalNameTable:aNameTable];
}
+ (void)loadCibNamed:(CPString)aName owner:(id)anOwner
+ (CPCib)loadCibNamed:(CPString)aName owner:(id)anOwner
{
if (![aName hasSuffix:@".cib"])
aName = [aName stringByAppendingString:@".cib"];
@@ -51,24 +51,24 @@ var CPCibOwner = @"CPCibOwner";
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
path = [bundle pathForResource:aName];
[self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner]];
return [self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner]];
}
- (void)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable
- (CPCib)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable
{
[[[CPCib alloc] initWithContentsOfURL:aFileName] instantiateCibWithExternalNameTable:aNameTable];
return [[[CPCib alloc] initWithContentsOfURL:aFileName] instantiateCibWithExternalNameTable:aNameTable];
}
+ (void)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable loadDelegate:aDelegate
+ (CPCib)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable loadDelegate:aDelegate
{
[[CPCib alloc]
return ([[CPCib alloc]
initWithContentsOfURL:anAbsolutePath
loadDelegate:[[_CPCibLoadDelegate alloc]
initWithLoadDelegate:aDelegate
externalNameTable:aNameTable]];
externalNameTable:aNameTable]]);
}
+ (void)loadCibNamed:(CPString)aName owner:(id)anOwner loadDelegate:(id)aDelegate
+ (CPCib)loadCibNamed:(CPString)aName owner:(id)anOwner loadDelegate:(id)aDelegate
{
if (![aName hasSuffix:@".cib"])
aName = [aName stringByAppendingString:@".cib"];
@@ -77,17 +77,17 @@ var CPCibOwner = @"CPCibOwner";
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
path = [bundle pathForResource:aName];
[self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner] loadDelegate:aDelegate];
return [self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner] loadDelegate:aDelegate];
}
- (void)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable loadDelegate:(id)aDelegate
- (CPCib)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable loadDelegate:(id)aDelegate
{
[[CPCib alloc]
return ([[CPCib alloc]
initWithCibNamed:aFileName
bundle:self
loadDelegate:[[_CPCibLoadDelegate alloc]
initWithLoadDelegate:aDelegate
externalNameTable:aNameTable]];
externalNameTable:aNameTable]]);
}
@end
@@ -118,4 +118,9 @@ var CPCibOwner = @"CPCibOwner";
[_loadDelegate cibDidFinishLoading:aCib];
}
- (void)cibDidFailToLoad:(CPCib)aCib
{
[_loadDelegate cibDidFailToLoad:aCib];
}
@end
+15 -5
View File
@@ -46,28 +46,28 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
- (id)initWithClassName:(CPString)aClassName resourceName:(CPString)aResourceName properties:(CPDictionary)properties
{
self = [super init];
if (self)
{
_className = aClassName;
_resourceName = aResourceName;
_properties = properties;
}
return self;
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_className = [aCoder decodeObjectForKey:_CPCibCustomResourceClassNameKey];
_resourceName = [aCoder decodeObjectForKey:_CPCibCustomResourceResourceNameKey];
_properties = [aCoder decodeObjectForKey:_CPCibCustomResourcePropertiesKey];
}
return self;
}
@@ -80,7 +80,7 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
- (id)awakeAfterUsingCoder:(CPCoder)aCoder
{
if ([aCoder respondsToSelector:@selector(bundle)] &&
if ([aCoder respondsToSelector:@selector(bundle)] &&
(![aCoder respondsToSelector:@selector(awakenCustomResources)] || [aCoder awakenCustomResources]))
if (_className === @"CPImage")
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:_properties.valueForKey(@"size")];
@@ -112,4 +112,14 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
return NO;
}
- (unsigned)loadStatus
{
return CPImageLoadStatusCompleted;
}
- (id)delegate
{
return nil;
}
@end
+3
View File
@@ -1,6 +1,9 @@
@import <Foundation/CPObject.j>
@import "CGGeometry.j"
@import "CPWindow.j"
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
+4 -8
View File
@@ -22,13 +22,10 @@
@import <Foundation/CPObject.j>
@import <AppKit/CABackingStore.j>
@import "CABackingStore.j"
@import <AppKit/CGContext.j>
@import <AppKit/CGGeometry.j>
#include "../CoreGraphics/CGGeometry.h"
#include "../CoreGraphics/CGAffineTransform.j"
@import "CGContext.j"
@import "CGGeometry.j"
#define DOM(aLayer) aLayer._DOMElement
@@ -777,8 +774,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
@ignore
*/
+ (void)runLoopUpdateLayers
{if (window.oops) {alert(window.latest); objj_debug_print_backtrace();}
window.loop = true;
{
for (UID in CALayerRegisteredRunLoopUpdates)
{
var layer = CALayerRegisteredRunLoopUpdates[UID],
+2 -5
View File
@@ -20,14 +20,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "CGGeometry.h"
#include "CGAffineTransform.h"
#define _function(inline) function inline { return _##inline; }
@import "CGGeometry.j"
#define _function(inline) function inline { return _##inline; }
_function(CGAffineTransformMake(a, b, c, d, tx, ty))
_function(CGAffineTransformMakeIdentity())
_function(CGAffineTransformMakeCopy(anAffineTransform))
+3 -4
View File
@@ -20,13 +20,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "CGGeometry.h"
#include "CGAffineTransform.h"
@import "CGGeometry.j"
@import "CGAffineTransform.j"
@import "CPCompatibility.j"
@import "CGGeometry.j"
@import "CGPath.j"
kCGLineCapButt = 0;
kCGLineCapRound = 1;
kCGLineCapSquare = 2;
+1
View File
@@ -63,6 +63,7 @@
#define _CGInsetMakeCopy(anInset) _CGInsetMake(anInset.top, anInset.right, anInset.bottom, anInset.left)
#define _CGInsetMakeZero() _CGInsetMake(0, 0, 0, 0)
#define _CGInsetIsEmpty(anInset) ((anInset).top === 0 && (anInset).right === 0 && (anInset).bottom === 0 && (anInset).left === 0)
#define _CGInsetEqualToInset(lhsInset, rhsInset) ((lhsInset).top === (rhsInset).top && (lhsInset).right === (rhsInset).right && (lhsInset).bottom === (rhsInset).bottom && (lhsInset).left === (rhsInset).left)
// DEPRECATED
#define _CGPointCreateCopy(aPoint) _CGPointMake(aPoint.x, aPoint.y)

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