Compare commits

...
900 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 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
643 changed files with 46553 additions and 7950 deletions
+9 -4
View File
@@ -36,8 +36,8 @@
@import "CPCibLoading.j" @import "CPCibLoading.j"
@import "CPCibOutletConnector.j" @import "CPCibOutletConnector.j"
@import "CPClipView.j" @import "CPClipView.j"
@import "CPCollectionViewItem.j"
@import "CPCollectionView.j" @import "CPCollectionView.j"
@import "CPCollectionViewItem.j"
@import "CPColor.j" @import "CPColor.j"
@import "CPColorPanel.j" @import "CPColorPanel.j"
@import "CPColorWell.j" @import "CPColorWell.j"
@@ -53,8 +53,10 @@
@import "CPFont.j" @import "CPFont.j"
@import "CPFontManager.j" @import "CPFontManager.j"
@import "CPGeometry.j" @import "CPGeometry.j"
@import "CPGraphics.j"
@import "CPImage.j" @import "CPImage.j"
@import "CPImageView.j" @import "CPImageView.j"
@import "CPKeyBinding.j"
@import "CPMenu.j" @import "CPMenu.j"
@import "CPMenuItem.j" @import "CPMenuItem.j"
@import "CPOpenPanel.j" @import "CPOpenPanel.j"
@@ -65,20 +67,22 @@
@import "CPProgressIndicator.j" @import "CPProgressIndicator.j"
@import "CPRadio.j" @import "CPRadio.j"
@import "CPResponder.j" @import "CPResponder.j"
@import "CPSearchField.j"
@import "CPScrollView.j"
@import "CPScroller.j" @import "CPScroller.j"
@import "CPScrollView.j"
@import "CPSearchField.j"
@import "CPSecureTextField.j" @import "CPSecureTextField.j"
@import "CPSegmentedControl.j" @import "CPSegmentedControl.j"
@import "CPShadow.j" @import "CPShadow.j"
@import "CPSlider.j" @import "CPSlider.j"
@import "CPSplitView.j" @import "CPSplitView.j"
@import "CPTabView.j"
@import "CPTableColumn.j" @import "CPTableColumn.j"
@import "CPTableView.j" @import "CPTableView.j"
@import "CPTabView.j"
@import "CPText.j"
@import "CPTextField.j" @import "CPTextField.j"
@import "CPToolbar.j" @import "CPToolbar.j"
@import "CPToolbarItem.j" @import "CPToolbarItem.j"
@import "CPTokenField.j"
@import "CPTreeNode.j" @import "CPTreeNode.j"
@import "CPView.j" @import "CPView.j"
@import "CPViewAnimation.j" @import "CPViewAnimation.j"
@@ -86,3 +90,4 @@
@import "CPWebView.j" @import "CPWebView.j"
@import "CPWindow.j" @import "CPWindow.j"
@import "CPWindowController.j" @import "CPWindowController.j"
@import "CPArrayController.j"
+46 -11
View File
@@ -26,11 +26,16 @@
@import <Foundation/CPIndexSet.j> @import <Foundation/CPIndexSet.j>
@import <Foundation/CPString.j> @import <Foundation/CPString.j>
@import <AppKit/CPView.j> @import "CPView.j"
@import "CPButton.j"
#import "CoreGraphics/CGGeometry.h"
/*!
@ingroup appkit
@class CPAccordionViewItem
<p>A CPAccordionViewItem represents a single section of a CPAccordionView.</p>
*/
@implementation CPAccordionViewItem : CPObject @implementation CPAccordionViewItem : CPObject
{ {
CPString _identifier @accessors(property=identifier); CPString _identifier @accessors(property=identifier);
@@ -43,6 +48,10 @@
return [self initWithIdentifier:@""]; 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 - (id)initWithIdentifier:(CPString)anIdentifier
{ {
self = [super init]; self = [super init];
@@ -55,6 +64,25 @@
@end @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 @implementation CPAccordionView : CPView
{ {
CPInteger _dirtyItemIndex; CPInteger _dirtyItemIndex;
@@ -64,7 +92,10 @@
CPMutableArray _itemViews; CPMutableArray _itemViews;
CPIndexSet _expandedItemIndexes; CPIndexSet _expandedItemIndexes;
} }
/*!
Initializes the receiver for usage with the specified bounding rectangle
@return the initialized view
*/
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
@@ -95,7 +126,11 @@
{ {
return _items; return _items;
} }
/*!
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 - (void)addItem:(CPAccordionViewItem)anItem
{ {
[self insertItem:anItem atIndex:_items.length]; [self insertItem:anItem atIndex:_items.length];
@@ -178,7 +213,7 @@
if ([itemView isCollapsed]) if ([itemView isCollapsed])
[self expandItemAtIndex:anIndex]; [self expandItemAtIndex:anIndex];
else else
[self collapseItemAtIndex:anIndex]; [self collapseItemAtIndex:anIndex];
} }
@@ -202,12 +237,12 @@
var itemView = _itemViews[anIndex]; var itemView = _itemViews[anIndex];
if (!itemView) if (!itemView)
return; return;
if (!isEnabled) if (!isEnabled)
[self collapseItemAtIndex:anIndex]; [self collapseItemAtIndex:anIndex];
else else
[self expandItemAtIndex:anIndex]; [self expandItemAtIndex:anIndex];
[itemView setEnabled:isEnabled]; [itemView setEnabled:isEnabled];
} }
@@ -235,7 +270,7 @@
{ {
if (_items.length <= 0) if (_items.length <= 0)
return [self setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), 0.0)]; return [self setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), 0.0)];
if (_dirtyItemIndex === CPNotFound) if (_dirtyItemIndex === CPNotFound)
return; return;
@@ -356,7 +391,7 @@
[_contentView setFrameSize:_CGSizeMake(aWidth, contentHeight)]; [_contentView setFrameSize:_CGSizeMake(aWidth, contentHeight)];
[self setFrame:_CGRectMake(0.0, aY, aWidth, contentHeight + headerHeight)]; [self setFrame:_CGRectMake(0.0, aY, aWidth, contentHeight + headerHeight)];
} }
} }
- (void)resizeSubviewsWithOldSize:(CGSize)aSize - (void)resizeSubviewsWithOldSize:(CGSize)aSize
@@ -373,7 +408,7 @@
/* /*
else if (aKeyPath === "itemHeaderPrototype") else if (aKeyPath === "itemHeaderPrototype")
{ {
} }
*/ */
} }
+258 -104
View File
@@ -26,39 +26,34 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import <Foundation/CPString.j> @import <Foundation/CPString.j>
@import <AppKit/CPApplication.j> @import "CPApplication.j"
@import <AppKit/CPButton.j> @import "CPButton.j"
@import <AppKit/CPColor.j> @import "CPColor.j"
@import <AppKit/CPFont.j> @import "CPFont.j"
@import <AppKit/CPImage.j> @import "CPImage.j"
@import <AppKit/CPImageView.j> @import "CPImageView.j"
@import <AppKit/CPPanel.j> @import "CPPanel.j"
@import <AppKit/CPTextField.j> @import "CPTextField.j"
/* /*
@global @global
@group CPAlertStyle @group CPAlertStyle
*/ */
CPWarningAlertStyle = 0; CPWarningAlertStyle = 0;
/* /*
@global @global
@group CPAlertStyle @group CPAlertStyle
*/ */
CPInformationalAlertStyle = 1; CPInformationalAlertStyle = 1;
/* /*
@global @global
@group CPAlertStyle @group CPAlertStyle
*/ */
CPCriticalAlertStyle = 2; CPCriticalAlertStyle = 2;
var CPAlertWarningImage,
CPAlertInformationImage,
CPAlertErrorImage;
/*! /*!
@ingroup appkit @ingroup appkit
CPAlert is an alert panel that can be displayed modally to present the CPAlert is an alert panel that can be displayed modally to present the
user with a message and one or more options. user with a message and one or more options.
@@ -74,41 +69,51 @@ var CPAlertWarningImage,
@delegate -(void)alertDidEnd:(CPAlert)theAlert returnCode:(int)returnCode; @delegate -(void)alertDidEnd:(CPAlert)theAlert returnCode:(int)returnCode;
Called when the user dismisses the alert by clicking one of the buttons. Called when the user dismisses the alert by clicking one of the buttons.
@param theAlert the alert panel that the user dismissed @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 representing the first button added to the alert which appears on the
right, 1 representing the next button to the left and so on) right, 1 representing the next button to the left and so on)
*/ */
@implementation CPAlert : CPObject @implementation CPAlert : CPView
{ {
CPPanel _alertPanel; CPPanel _alertPanel;
CPTextField _messageLabel; CPTextField _messageLabel;
CPTextField _informativeLabel;
CPImageView _alertImageView; CPImageView _alertImageView;
CPAlertStyle _alertStyle; CPAlertStyle _alertStyle;
CPString _windowTitle; CPString _windowTitle;
int _windowStyle; int _windowStyle;
int _buttonCount;
CPArray _buttons; CPArray _buttons;
id _delegate; id _delegate;
SEL _didEndSelector;
id _modalDelegate;
} }
+ (void)initialize + (CPString)defaultThemeClass
{ {
if (self != CPAlert) return @"alert";
return; }
var bundle = [CPBundle bundleForClass:[self class]]; + (id)themeAttributes
{
CPAlertWarningImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-warning.png"] return [CPDictionary dictionaryWithObjects:[CGSizeMake(400.0, 110.0), CGInsetMake(15, 15, 15, 50), 6, 10,
size:CGSizeMake(32.0, 32.0)]; CPJustifiedTextAlignment, [CPColor blackColor], [CPFont boldSystemFontOfSize:13.0], [CPNull null], CGSizeMakeZero(),
CPJustifiedTextAlignment, [CPColor blackColor], [CPFont systemFontOfSize:12.0], [CPNull null], CGSizeMakeZero(),
CPAlertInformationImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-information.png"] CGPointMake(15, 12),
size:CGSizeMake(32.0, 32.0)]; [CPNull null],
[CPNull null],
CPAlertErrorImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-error.png"] [CPNull null]
size:CGSizeMake(32.0, 32.0)]; ]
forKeys:[@"size", @"content-inset", @"informative-offset", @"button-offset",
@"message-text-alignment", @"message-text-color", @"message-text-font", @"message-text-shadow-color", @"message-text-shadow-offset",
@"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]) if (self = [super init])
{ {
_buttonCount = 0;
_buttons = [CPArray array]; _buttons = [CPArray array];
_alertStyle = CPWarningAlertStyle; _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; 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. @param styleMask - Either CPHUDBackgroundWindowMask or nil for standard.
*/ */
- (void)setWindowStyle:(int)styleMask - (void)setWindowStyle:(int)styleMask
{ {
_windowStyle = 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]; // We'll need to recreate the panel to get the new window style.
for(var i=0; i < count; i++) _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]; while (count--)
[contentView addSubview:_buttons[count]];
[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];
} }
else
if (!_messageLabel) [self addButtonWithTitle:@"OK"];
{
var bounds = [[_alertPanel contentView] bounds];
_messageLabel = [[CPTextField alloc] initWithFrame:CGRectMake(57.0, 10.0, CGRectGetWidth(bounds) - 73.0, 62.0)]; [contentView addSubview:_messageLabel];
[_messageLabel setFont:[CPFont boldSystemFontOfSize:13.0]]; [contentView addSubview:_alertImageView];
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping]; [contentView addSubview:_informativeLabel];
[_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];
} }
/*! /*!
@@ -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. @param messageText - Message text for the alert.
*/ */
- (void)setMessageText:(CPString)messageText - (void)setMessageText:(CPString)messageText
@@ -239,41 +243,157 @@ var CPAlertWarningImage,
[_messageLabel setStringValue:messageText]; [_messageLabel setStringValue:messageText];
} }
/*! /*!
Return's the receiver's message text body. Returns the receiver's message text body.
*/ */
- (CPString)messageText - (CPString)messageText
{ {
return [_messageLabel stringValue]; 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. 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. 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 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. You really shouldn't need more than 3 buttons.
*/ */
- (void)addButtonWithTitle:(CPString)title - (void)addButtonWithTitle:(CPString)title
{ {
var bounds = [[_alertPanel contentView] bounds], 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 setTitle:title];
[button setTarget:self]; [button setTarget:self];
[button setTag:_buttonCount]; [button setTag:_buttonCount];
[button setAction:@selector(_notifyDelegate:)]; [button setAction:@selector(_dismissAlert:)];
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
[button setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
[[_alertPanel contentView] addSubview:button]; [[_alertPanel contentView] addSubview:button];
if (_buttonCount == 0)
[_alertPanel setDefaultButton:button];
_buttonCount++; if (_buttonCount == 0)
[_buttons addObject:button]; [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 - (void)runModal
{ {
var theTitle; [self layoutPanel];
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];
[CPApp runModalForWindow:_alertPanel]; [CPApp runModalForWindow:_alertPanel];
} }
/* @ignore */ /*!
- (void)_notifyDelegate:(id)button Runs the receiver modally as an alert sheet attached to a specified window.
{
[CPApp abortModal];
[_alertPanel close];
if (_delegate && [_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)]) @param window The parent window for the sheet.
[_delegate alertDidEnd:self returnCode:[button tag]]; @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 @end
+27 -27
View File
@@ -48,14 +48,14 @@ CPAnimationLinear = 3;
ACTUAL_FRAME_RATE = 0; ACTUAL_FRAME_RATE = 0;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPAnimation @class CPAnimation
Manages an animation. Contains timing and progress information. Manages an animation. Contains timing and progress information.
@par Delegate Methods @par Delegate Methods
@delegate -(BOOL)animationShouldStart:(CPAnimation)animation; @delegate -(BOOL)animationShouldStart:(CPAnimation)animation;
Called at the beginning of \c -startAnimation. Called at the beginning of \c -startAnimation.
@param animation the animation that will start @param animation the animation that will start
@@ -81,13 +81,13 @@ ACTUAL_FRAME_RATE = 0;
{ {
CPTimeInterval _lastTime; CPTimeInterval _lastTime;
CPTimeInterval _duration; CPTimeInterval _duration;
CPAnimationCurve _animationCurve; CPAnimationCurve _animationCurve;
CAMediaTimingFunction _timingFunction; CAMediaTimingFunction _timingFunction;
float _frameRate; float _frameRate;
float _progress; float _progress;
id _delegate; id _delegate;
CPTimer _timer; CPTimer _timer;
} }
@@ -101,7 +101,7 @@ ACTUAL_FRAME_RATE = 0;
- (id)initWithDuration:(float)aDuration animationCurve:(CPAnimationCurve)anAnimationCurve - (id)initWithDuration:(float)aDuration animationCurve:(CPAnimationCurve)anAnimationCurve
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_progress = 0.0; _progress = 0.0;
@@ -110,14 +110,14 @@ ACTUAL_FRAME_RATE = 0;
[self setAnimationCurve:anAnimationCurve]; [self setAnimationCurve:anAnimationCurve];
} }
return self; return self;
} }
/*! /*!
Sets the animation's pace. Sets the animation's pace.
@param anAnimationCurve 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 - (void)setAnimationCurve:(CPAnimationCurve)anAnimationCurve
{ {
@@ -125,13 +125,13 @@ ACTUAL_FRAME_RATE = 0;
{ {
case CPAnimationEaseInOut: timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut; case CPAnimationEaseInOut: timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut;
break; break;
case CPAnimationEaseIn: timingFunctionName = kCAMediaTimingFunctionEaseIn; case CPAnimationEaseIn: timingFunctionName = kCAMediaTimingFunctionEaseIn;
break; break;
case CPAnimationEaseOut: timingFunctionName = kCAMediaTimingFunctionEaseOut; case CPAnimationEaseOut: timingFunctionName = kCAMediaTimingFunctionEaseOut;
break; break;
case CPAnimationLinear: timingFunctionName = kCAMediaTimingFunctionLinear; case CPAnimationLinear: timingFunctionName = kCAMediaTimingFunctionLinear;
break; break;
@@ -139,7 +139,7 @@ ACTUAL_FRAME_RATE = 0;
reason:"Invalid value provided for animation curve"]; reason:"Invalid value provided for animation curve"];
break; break;
} }
_animationCurve = anAnimationCurve; _animationCurve = anAnimationCurve;
_timingFunction = [CAMediaTimingFunction functionWithName:timingFunctionName]; _timingFunction = [CAMediaTimingFunction functionWithName:timingFunctionName];
} }
@@ -161,7 +161,7 @@ ACTUAL_FRAME_RATE = 0;
{ {
if (aDuration < 0) if (aDuration < 0)
[CPException raise:CPInvalidArgumentException reason:"aDuration can't be negative"]; [CPException raise:CPInvalidArgumentException reason:"aDuration can't be negative"];
_duration = aDuration; _duration = aDuration;
} }
@@ -182,7 +182,7 @@ ACTUAL_FRAME_RATE = 0;
{ {
if (frameRate < 0) if (frameRate < 0)
[CPException raise:CPInvalidArgumentException reason:"frameRate can't be negative"]; [CPException raise:CPInvalidArgumentException reason:"frameRate can't be negative"];
_frameRate = frameRate; _frameRate = frameRate;
} }
@@ -221,13 +221,13 @@ ACTUAL_FRAME_RATE = 0;
// If we're already animating, or our delegate stops us, animate. // If we're already animating, or our delegate stops us, animate.
if (_timer || _delegate && [_delegate respondsToSelector:@selector(animationShouldStart:)] && ![_delegate animationShouldStart:self]) if (_timer || _delegate && [_delegate respondsToSelector:@selector(animationShouldStart:)] && ![_delegate animationShouldStart:self])
return; return;
if (_progress === 1.0) if (_progress === 1.0)
_progress = 0.0; _progress = 0.0;
ACTUAL_FRAME_RATE = 0; ACTUAL_FRAME_RATE = 0;
_lastTime = new Date(); _lastTime = new Date();
_timer = [CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(animationTimerDidFire:) userInfo:nil repeats:YES]; _timer = [CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(animationTimerDidFire:) userInfo:nil repeats:YES];
} }
@@ -242,14 +242,14 @@ ACTUAL_FRAME_RATE = 0;
_lastTime = currentTime; _lastTime = currentTime;
++ACTUAL_FRAME_RATE; ++ACTUAL_FRAME_RATE;
[self setCurrentProgress:progress]; [self setCurrentProgress:progress];
if (progress === 1.0) if (progress === 1.0)
{ {
[_timer invalidate]; [_timer invalidate];
_timer = nil; _timer = nil;
if ([_delegate respondsToSelector:@selector(animationDidEnd:)]) if ([_delegate respondsToSelector:@selector(animationDidEnd:)])
[_delegate animationDidEnd:self]; [_delegate animationDidEnd:self];
} }
@@ -262,10 +262,10 @@ ACTUAL_FRAME_RATE = 0;
{ {
if (!_timer) if (!_timer)
return; return;
[_timer invalidate]; [_timer invalidate];
_timer = nil; _timer = nil;
if ([_delegate respondsToSelector:@selector(animationDidStop:)]) if ([_delegate respondsToSelector:@selector(animationDidStop:)])
[_delegate animationDidStop:self]; [_delegate animationDidStop:self];
} }
@@ -302,16 +302,16 @@ ACTUAL_FRAME_RATE = 0;
- (float)currentValue - (float)currentValue
{ {
var t = [self currentProgress]; var t = [self currentProgress];
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)]) if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
return [_delegate animation:self valueForProgress:t]; return [_delegate animation:self valueForProgress:t];
var c1 = [], var c1 = [],
c2 = []; c2 = [];
[_timingFunction getControlPointAtIndex:1 values:c1]; [_timingFunction getControlPointAtIndex:1 values:c1];
[_timingFunction getControlPointAtIndex:2 values:c2]; [_timingFunction getControlPointAtIndex:2 values:c2];
return CubicBezierAtTime(t,c1[0],c1[1],c2[0],c2[1],_duration); return CubicBezierAtTime(t,c1[0],c1[1],c2[0],c2[1],_duration);
} }
@@ -332,7 +332,7 @@ var CubicBezierAtTime = function CubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration)
function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));}; function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));};
// Given an x value, find a parametric value it came from. // Given an x value, find a parametric value it came from.
function solveCurveX(x,epsilon) {var t0,t1,t2,x2,d2,i; 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. // First try a few iterations of Newton's method -- normally very fast.
for(t2=x, i=0; i<8; i++) {x2=sampleCurveX(t2)-x; if(fabs(x2)<epsilon) {return t2;} d2=sampleCurveDerivativeX(t2); if(fabs(d2)<1e-6) {break;} t2=t2-x2/d2;} for(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. // Fall back to the bisection method for reliability.
+171 -146
View File
@@ -31,7 +31,6 @@
@import "CPCibLoading.j" @import "CPCibLoading.j"
@import "CPPlatform.j" @import "CPPlatform.j"
#include "Platform/Platform.h"
var CPMainCibFile = @"CPMainCibFile", var CPMainCibFile = @"CPMainCibFile",
CPMainCibFileHumanFriendly = @"Main cib file base name"; CPMainCibFileHumanFriendly = @"Main cib file base name";
@@ -54,7 +53,7 @@ CPRunStoppedResponse = -1000;
CPRunAbortedResponse = -1001; CPRunAbortedResponse = -1001;
CPRunContinuesResponse = -1002; CPRunContinuesResponse = -1002;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPApplication @class CPApplication
@@ -62,7 +61,7 @@ CPRunContinuesResponse = -1002;
Every GUI application has exactly one instance of CPApplication (or of a custom subclass of 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 CPApplication). Your program's main() function can create that instance by calling the
\c CPApplicationMain function. A simple example looks like this: \c CPApplicationMain function. A simple example looks like this:
<pre> <pre>
function main(args, namedArgs) function main(args, namedArgs)
{ {
@@ -82,25 +81,25 @@ CPRunContinuesResponse = -1002;
@implementation CPApplication : CPResponder @implementation CPApplication : CPResponder
{ {
CPArray _eventListeners; CPArray _eventListeners;
CPEvent _currentEvent; CPEvent _currentEvent;
CPArray _windows; CPArray _windows;
CPWindow _keyWindow; CPWindow _keyWindow;
CPWindow _mainWindow; CPWindow _mainWindow;
CPWindow _previousKeyWindow; CPWindow _previousKeyWindow;
CPWindow _previousMainWindow; CPWindow _previousMainWindow;
CPMenu _mainMenu; CPMenu _mainMenu;
CPDocumentController _documentController; CPDocumentController _documentController;
CPModalSession _currentSession; CPModalSession _currentSession;
// //
id _delegate; id _delegate;
BOOL _finishedLaunching; BOOL _finishedLaunching;
BOOL _isActive; BOOL _isActive;
CPDictionary _namedArgs; CPDictionary _namedArgs;
CPArray _args; CPArray _args;
CPString _fullArgsString; CPString _fullArgsString;
@@ -108,6 +107,8 @@ CPRunContinuesResponse = -1002;
CPImage _applicationIconImage; CPImage _applicationIconImage;
CPPanel _aboutPanel; CPPanel _aboutPanel;
CPThemeBlend _themeBlend @accessors(property=themeBlend);
} }
/*! /*!
@@ -119,7 +120,7 @@ CPRunContinuesResponse = -1002;
{ {
if (!CPApp) if (!CPApp)
CPApp = [[CPApplication alloc] init]; CPApp = [[CPApplication alloc] init];
return CPApp; return CPApp;
} }
@@ -131,73 +132,18 @@ CPRunContinuesResponse = -1002;
- (id)init - (id)init
{ {
self = [super init]; self = [super init];
CPApp = self;
if (self) if (self)
{ {
_eventListeners = []; _eventListeners = [];
_windows = []; _windows = [];
[_windows addObject:nil]; [_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; return self;
} }
@@ -278,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 // We also want to set the default cursor on the body, so that buttons and things don't have an iBeam
[[CPCursor arrowCursor] set]; [[CPCursor arrowCursor] set];
var bundle = [CPBundle mainBundle], var bundle = [CPBundle mainBundle],
types = [bundle objectForInfoDictionaryKey:@"CPBundleDocumentTypes"]; types = [bundle objectForInfoDictionaryKey:@"CPBundleDocumentTypes"];
if ([types count] > 0) if ([types count] > 0)
_documentController = [CPDocumentController sharedDocumentController]; _documentController = [CPDocumentController sharedDocumentController];
var delegateClassName = [bundle objectForInfoDictionaryKey:@"CPApplicationDelegateClass"]; var delegateClassName = [bundle objectForInfoDictionaryKey:@"CPApplicationDelegateClass"];
if (delegateClassName) if (delegateClassName)
{ {
var delegateClass = objj_getClass(delegateClassName); var delegateClass = objj_getClass(delegateClassName);
if (delegateClass) if (delegateClass)
if ([_documentController class] == delegateClass) if ([_documentController class] == delegateClass)
[self setDelegate:_documentController]; [self setDelegate:_documentController];
else else
[self setDelegate:[[delegateClass alloc] init]]; [self setDelegate:[[delegateClass alloc] init]];
} }
var defaultCenter = [CPNotificationCenter defaultCenter]; var defaultCenter = [CPNotificationCenter defaultCenter];
[defaultCenter [defaultCenter
postNotificationName:CPApplicationWillFinishLaunchingNotification postNotificationName:CPApplicationWillFinishLaunchingNotification
object:self]; object:self];
@@ -380,7 +326,9 @@ CPRunContinuesResponse = -1002;
applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"], applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"],
copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"]; 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], aboutPanel = [aboutPanelController window],
contentView = [aboutPanel contentView], contentView = [aboutPanel contentView],
imageView = [contentView viewWithTag:1], imageView = [contentView viewWithTag:1],
@@ -388,14 +336,14 @@ CPRunContinuesResponse = -1002;
versionLabel = [contentView viewWithTag:3], versionLabel = [contentView viewWithTag:3],
copyrightLabel = [contentView viewWithTag:4], copyrightLabel = [contentView viewWithTag:4],
standardPath = [[CPBundle bundleForClass:[self class]] pathForResource:@"standardApplicationIcon.png"]; standardPath = [[CPBundle bundleForClass:[self class]] pathForResource:@"standardApplicationIcon.png"];
// FIXME move this into the CIB eventually // FIXME move this into the CIB eventually
[applicationLabel setFont:[CPFont boldSystemFontOfSize:14.0]]; [applicationLabel setFont:[CPFont boldSystemFontOfSize:14.0]];
[applicationLabel setAlignment:CPCenterTextAlignment]; [applicationLabel setAlignment:CPCenterTextAlignment];
[versionLabel setAlignment:CPCenterTextAlignment]; [versionLabel setAlignment:CPCenterTextAlignment];
[copyrightLabel setAlignment:CPCenterTextAlignment]; [copyrightLabel setAlignment:CPCenterTextAlignment];
[imageView setImage:applicationIcon || [[CPImage alloc] initWithContentsOfFile:standardPath [imageView setImage:applicationIcon || [[CPImage alloc] initWithContentsOfFile:standardPath
size:CGSizeMake(256, 256)]]; size:CGSizeMake(256, 256)]];
[applicationLabel setStringValue:applicationTitle || ""]; [applicationLabel setStringValue:applicationTitle || ""];
@@ -499,10 +447,10 @@ CPRunContinuesResponse = -1002;
return; return;
// raise exception; // raise exception;
} }
_currentSession._state = aCode; _currentSession._state = aCode;
_currentSession = _currentSession._previous; _currentSession = _currentSession._previous;
// if (aCode == CPRunAbortedResponse) // if (aCode == CPRunAbortedResponse)
[self _removeRunModalLoop]; [self _removeRunModalLoop];
} }
@@ -511,12 +459,12 @@ CPRunContinuesResponse = -1002;
- (void)_removeRunModalLoop - (void)_removeRunModalLoop
{ {
var count = _eventListeners.length; var count = _eventListeners.length;
while (count--) while (count--)
if (_eventListeners[count]._callback === _CPRunModalLoop) if (_eventListeners[count]._callback === _CPRunModalLoop)
{ {
_eventListeners.splice(count, 1); _eventListeners.splice(count, 1);
return; return;
} }
} }
@@ -554,12 +502,13 @@ CPRunContinuesResponse = -1002;
{ {
aModalSession._previous = _currentSession; aModalSession._previous = _currentSession;
_currentSession = aModalSession; _currentSession = aModalSession;
var theWindow = aModalSession._window; var theWindow = aModalSession._window;
[theWindow center]; [theWindow center];
[theWindow makeKeyAndOrderFront:self]; [theWindow makeKeyWindow];
[theWindow orderFront:self];
// [theWindow._bridge _obscureWindowsBelowModalWindow]; // [theWindow._bridge _obscureWindowsBelowModalWindow];
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO]; [CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
@@ -573,7 +522,7 @@ CPRunContinuesResponse = -1002;
{ {
if (!_currentSession) if (!_currentSession)
return nil; return nil;
return _currentSession._window; return _currentSession._window;
} }
@@ -618,7 +567,7 @@ CPRunContinuesResponse = -1002;
{ {
if (_eventListeners[_eventListeners.length - 1]._mask & (1 << [anEvent type])) if (_eventListeners[_eventListeners.length - 1]._mask & (1 << [anEvent type]))
_eventListeners.pop()._callback(anEvent); _eventListeners.pop()._callback(anEvent);
return; return;
} }
@@ -670,7 +619,11 @@ CPRunContinuesResponse = -1002;
*/ */
- (CPArray)orderedWindows - (CPArray)orderedWindows
{ {
#if PLATFORM(DOM)
return CPWindowObjectList(); return CPWindowObjectList();
#else
return [];
#endif
} }
- (void)hide:(id)aSender - (void)hide:(id)aSender
@@ -729,11 +682,11 @@ CPRunContinuesResponse = -1002;
if ([super tryToPerform:anAction with:anObject]) if ([super tryToPerform:anAction with:anObject])
return YES; return YES;
if([_delegate respondsToSelector:anAction]) if ([_delegate respondsToSelector:anAction])
{ {
[_delegate performSelector:anAction withObject:anObject]; [_delegate performSelector:anAction withObject:anObject];
return YES; return YES;
} }
@@ -753,9 +706,9 @@ CPRunContinuesResponse = -1002;
if (!target) if (!target)
return NO; return NO;
[target performSelector:anAction withObject:aSender]; [target performSelector:anAction withObject:aSender];
return YES; return YES;
} }
@@ -774,10 +727,10 @@ CPRunContinuesResponse = -1002;
{ {
if (!anAction) if (!anAction)
return nil; return nil;
if (aTarget) if (aTarget)
return aTarget; return aTarget;
return [self targetForAction:anAction]; return [self targetForAction:anAction];
} }
@@ -802,28 +755,28 @@ CPRunContinuesResponse = -1002;
{ {
var responder = [aWindow firstResponder], var responder = [aWindow firstResponder],
checkWindow = YES; checkWindow = YES;
while (responder) while (responder)
{ {
if ([responder respondsToSelector:anAction]) if ([responder respondsToSelector:anAction])
return responder; return responder;
if (responder == aWindow) if (responder == aWindow)
checkWindow = NO; checkWindow = NO;
responder = [responder nextResponder]; responder = [responder nextResponder];
} }
if (checkWindow && [aWindow respondsToSelector:anAction]) if (checkWindow && [aWindow respondsToSelector:anAction])
return aWindow; return aWindow;
var delegate = [aWindow delegate]; var delegate = [aWindow delegate];
if ([delegate respondsToSelector:anAction]) if ([delegate respondsToSelector:anAction])
return delegate; return delegate;
var windowController = [aWindow windowController]; var windowController = [aWindow windowController];
if ([windowController respondsToSelector:anAction]) if ([windowController respondsToSelector:anAction])
return windowController; return windowController;
@@ -852,26 +805,26 @@ CPRunContinuesResponse = -1002;
{ {
if (!anAction) if (!anAction)
return nil; return nil;
var target = [self _targetForWindow:[self keyWindow] action:anAction]; var target = [self _targetForWindow:[self keyWindow] action:anAction];
if (target) if (target)
return target; return target;
target = [self _targetForWindow:[self mainWindow] action:anAction]; target = [self _targetForWindow:[self mainWindow] action:anAction];
if (target) if (target)
return target; return target;
if ([self respondsToSelector:anAction]) if ([self respondsToSelector:anAction])
return self; return self;
if ([_delegate respondsToSelector:anAction]) if ([_delegate respondsToSelector:anAction])
return _delegate; return _delegate;
if ([_documentController respondsToSelector:anAction]) if ([_documentController respondsToSelector:anAction])
return _documentController; return _documentController;
return nil; return nil;
} }
@@ -901,30 +854,31 @@ CPRunContinuesResponse = -1002;
@param aContextInfo @param aContextInfo
*/ */
- (void)beginSheet:(CPWindow)aSheet modalForWindow:(CPWindow)aWindow modalDelegate:(id)aModalDelegate didEndSelector:(SEL)aDidEndSelector contextInfo:(id)aContextInfo - (void)beginSheet:(CPWindow)aSheet modalForWindow:(CPWindow)aWindow modalDelegate:(id)aModalDelegate didEndSelector:(SEL)aDidEndSelector contextInfo:(id)aContextInfo
{ {
var styleMask = [aSheet styleMask]; var styleMask = [aSheet styleMask];
if (!(styleMask & CPDocModalWindowMask)) if (!(styleMask & CPDocModalWindowMask))
{ {
[CPException raise:CPInternalInconsistencyException reason:@"Currently only CPDocModalWindowMask style mask is supported for attached sheets"]; [CPException raise:CPInternalInconsistencyException reason:@"Currently only CPDocModalWindowMask style mask is supported for attached sheets"];
return; return;
} }
[aWindow orderFront:self]; [aWindow orderFront:self];
[aSheet setPlatformWindow:[aWindow platformWindow]];
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo]; [aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
} }
- (void)endSheet:(CPWindow)sheet returnCode:(int)returnCode - (void)endSheet:(CPWindow)sheet returnCode:(int)returnCode
{ {
var count = [_windows count]; var count = [_windows count];
while (--count >= 0) while (--count >= 0)
{ {
var aWindow = [_windows objectAtIndex:count]; var aWindow = [_windows objectAtIndex:count],
var context = aWindow._sheetContext; context = aWindow._sheetContext;
if (context != nil && context["sheet"] === sheet) if (context != nil && context["sheet"] === sheet)
{ {
context["returnCode"] = returnCode; context["returnCode"] = returnCode;
[aWindow _detachSheetWindow]; [aWindow _detachSheetWindow];
return; return;
} }
@@ -938,40 +892,40 @@ CPRunContinuesResponse = -1002;
- (CPArray)arguments - (CPArray)arguments
{ {
if(_fullArgsString !== window.location.hash) if (_fullArgsString !== window.location.hash)
[self _reloadArguments]; [self _reloadArguments];
return _args; return _args;
} }
- (void)setArguments:(CPArray)args - (void)setArguments:(CPArray)args
{ {
if(!args || args.length == 0) if (!args || args.length == 0)
{ {
_args = []; _args = [];
window.location.hash = @"#"; window.location.hash = @"#";
return; return;
} }
if([args class] != CPArray) if ([args class] != CPArray)
args = [CPArray arrayWithObject:args]; args = [CPArray arrayWithObject:args];
_args = args; _args = args;
var toEncode = [_args copy]; 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]); toEncode[i] = encodeURIComponent(toEncode[i]);
var hash = [toEncode componentsJoinedByString:@"/"]; var hash = [toEncode componentsJoinedByString:@"/"];
window.location.hash = @"#" + hash; window.location.hash = @"#" + hash;
} }
- (void)_reloadArguments - (void)_reloadArguments
{ {
_fullArgsString = window.location.hash; _fullArgsString = window.location.hash;
if (_fullArgsString.length) if (_fullArgsString.length)
{ {
var args = _fullArgsString.substring(1).split("/"); var args = _fullArgsString.substring(1).split("/");
@@ -1006,18 +960,18 @@ CPRunContinuesResponse = -1002;
- (void)_willBecomeActive - (void)_willBecomeActive
{ {
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillBecomeActiveNotification [[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillBecomeActiveNotification
object:self object:self
userInfo:nil]; userInfo:nil];
} }
- (void)_didBecomeActive - (void)_didBecomeActive
{ {
if (![self keyWindow] && _previousKeyWindow && if (![self keyWindow] && _previousKeyWindow &&
[[self windows] indexOfObjectIdenticalTo:_previousKeyWindow] !== CPNotFound) [[self windows] indexOfObjectIdenticalTo:_previousKeyWindow] !== CPNotFound)
[_previousKeyWindow makeKeyWindow]; [_previousKeyWindow makeKeyWindow];
if (![self mainWindow] && _previousMainWindow && if (![self mainWindow] && _previousMainWindow &&
[[self windows] indexOfObjectIdenticalTo:_previousMainWindow] !== CPNotFound) [[self windows] indexOfObjectIdenticalTo:_previousMainWindow] !== CPNotFound)
[_previousMainWindow makeMainWindow]; [_previousMainWindow makeMainWindow];
@@ -1031,15 +985,15 @@ CPRunContinuesResponse = -1002;
_previousKeyWindow = nil; _previousKeyWindow = nil;
_previousMainWindow = nil; _previousMainWindow = nil;
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidBecomeActiveNotification [[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidBecomeActiveNotification
object:self object:self
userInfo:nil]; userInfo:nil];
} }
- (void)_willResignActive - (void)_willResignActive
{ {
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillResignActiveNotification [[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillResignActiveNotification
object:self object:self
userInfo:nil]; userInfo:nil];
} }
@@ -1060,14 +1014,13 @@ CPRunContinuesResponse = -1002;
[_previousMainWindow resignMainWindow]; [_previousMainWindow resignMainWindow];
} }
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidResignActiveNotification [[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidResignActiveNotification
object:self object:self
userInfo:nil]; userInfo:nil];
} }
+ (CPString)defaultThemeName + (CPString)defaultThemeName
{ {
// FIXME: don't hardcode
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo"); return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
} }
@@ -1083,13 +1036,14 @@ var _CPEventListenerMake = function(anEventMask, aCallback)
return { _mask:anEventMask, _callback: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]; [CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
var theWindow = [anEvent window], var theWindow = [anEvent window],
modalSession = CPApp._currentSession; modalSession = CPApp._currentSession;
if (theWindow == modalSession._window || [theWindow worksWhenModal]) if (theWindow == modalSession._window || [theWindow worksWhenModal])
[theWindow sendEvent:anEvent]; [theWindow sendEvent:anEvent];
} }
@@ -1161,8 +1115,15 @@ var _CPAppBootstrapperActions = nil;
+ (BOOL)loadDefaultTheme + (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]; [blend loadWithDelegate:self];
return YES; return YES;
@@ -1170,6 +1131,7 @@ var _CPAppBootstrapperActions = nil;
+ (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend + (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend
{ {
[[CPApplication sharedApplication] setThemeBlend:aThemeBlend];
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]]; [CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
[self performActions]; [self performActions];
@@ -1188,10 +1150,73 @@ var _CPAppBootstrapperActions = nil;
return YES; return YES;
} }
else
[self loadCiblessBrowserMainMenu];
return NO; 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 + (void)cibDidFinishLoading:(CPCib)aCib
{ {
[self performActions]; [self performActions];
@@ -1204,7 +1229,7 @@ var _CPAppBootstrapperActions = nil;
+ (void)reset + (void)reset
{ {
_CPAppBootstrapperActions = nil; _CPAppBootstrapperActions = nil;
} }
@end @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. * Created by Ross Boucher.
* Copyright 2009, 280 North, Inc. * 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * 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 * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright 2009 280 North, Inc. * Copyright 2009 280 North, Inc.
*/ */
@import <AppKit/CPGraphicsContext.j>
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import "CPGraphicsContext.j"
// Class defaults // Class defaults
var DefaultLineWidth = 1.0; var DefaultLineWidth = 1.0;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPBezierPath @class CPBezierPath
A CPBezierPath allows you to create paths for drawing to the screen using a simpler API than CoreGraphics. A CPBezierPath allows you to create paths for drawing to the screen using a simpler API than CoreGraphics.
Paths can form any shape, including regular polgyons like squares and triangles; circles, arcs; or complex Paths can form any shape, including regular 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 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). 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 + (CPBezierPath)bezierPathWithOvalInRect:(CGRect)rect
{ {
var path = [self bezierPath]; var path = [self bezierPath];
[path appendBezierPathWithOvalInRect:rect]; [path appendBezierPathWithOvalInRect:rect];
return path; return path;
} }
@@ -76,9 +77,9 @@ var DefaultLineWidth = 1.0;
+ (CPBezierPath)bezierPathWithRect:(CGRect)rect + (CPBezierPath)bezierPathWithRect:(CGRect)rect
{ {
var path = [self bezierPath]; var path = [self bezierPath];
[path appendBezierPathWithRect:rect]; [path appendBezierPathWithRect:rect];
return path; return path;
} }
+176 -52
View File
@@ -19,25 +19,33 @@
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CPView.j" @import "CPView.j"
// CPBoxType
CPBoxPrimary = 0;
CPBoxSecondary = 1;
CPBoxSeperator = 2;
CPBoxOldStyle = 3;
CPBoxCustom = 4;
// CPBorderType // CPBorderType
CPNoBorder = 0; CPNoBorder = 0;
CPLineBorder = 1; CPLineBorder = 1;
CPBezelBorder = 2; CPBezelBorder = 2;
CPGrooveBorder = 3; CPGrooveBorder = 3;
@implementation CPBox : CPView @implementation CPBox : CPView
{ {
CPBoxType _boxType;
CPBorderType _borderType; CPBorderType _borderType;
CPColor _borderColor; CPColor _borderColor;
CPColor _fillColor; CPColor _fillColor;
float _cornerRadius; float _cornerRadius;
float _borderWidth; float _borderWidth;
CPSize _contentMargin; CPSize _contentMargin;
CPView _contentView; CPView _contentView;
} }
@@ -50,18 +58,19 @@ CPGrooveBorder = 3;
[box setFrameFromContentFrame:[aView frame]]; [box setFrameFromContentFrame:[aView frame]];
[enclosingView replaceSubview:aView with:box]; [enclosingView replaceSubview:aView with:box];
[box setContentView:aView]; [box setContentView:aView];
return box; return box;
} }
- (id)initWithFrame:(CPRect)frameRect - (id)initWithFrame:(CPRect)frameRect
{ {
self = [super initWithFrame:frameRect]; self = [super initWithFrame:frameRect];
if (self) if (self)
{ {
_borderType = CPBezelBorder;
_fillColor = [CPColor clearColor]; _fillColor = [CPColor clearColor];
_borderColor = [CPColor blackColor]; _borderColor = [CPColor blackColor];
@@ -69,7 +78,9 @@ CPGrooveBorder = 3;
_contentMargin = CGSizeMake(0.0, 0.0); _contentMargin = CGSizeMake(0.0, 0.0);
_contentView = [[CPView alloc] initWithFrame:[self bounds]]; _contentView = [[CPView alloc] initWithFrame:[self bounds]];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[self setAutoresizesSubviews:YES];
[self addSubview:_contentView]; [self addSubview:_contentView];
} }
@@ -88,9 +99,26 @@ CPGrooveBorder = 3;
return _borderType; 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]; [self setNeedsDisplay:YES];
} }
@@ -161,9 +189,10 @@ CPGrooveBorder = 3;
return; return;
[aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)]; [aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)];
[aView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[self replaceSubview:_contentView with:aView]; [self replaceSubview:_contentView with:aView];
_contentView = aView; _contentView = aView;
} }
- (CPSize)contentViewMargins - (CPSize)contentViewMargins
@@ -173,9 +202,9 @@ CPGrooveBorder = 3;
- (void)setContentViewMargins:(CPSize)size - (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"]; [CPException raise:CPGenericException reason:@"Margins must be positive"];
_contentMargin = CGSizeMakeCopy(size); _contentMargin = CGSizeMakeCopy(size);
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
} }
@@ -189,56 +218,151 @@ CPGrooveBorder = 3;
- (void)sizeToFit - (void)sizeToFit
{ {
var contentFrame = [_contentView frame]; 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)]; contentFrame.size.height + _contentMargin.height * 2)];
[_contentView setFrameOrigin:CGPointMake(_contentMargin.width, _contentMargin.height)]; [_contentView setFrameOrigin:CGPointMake(_contentMargin.width, _contentMargin.height)];
} }
- (void)drawRect:(CPRect)rect - (void)drawRect:(CPRect)rect
{ {
var bounds = [self bounds], if (_borderType === CPNoBorder)
aContext = [[CPGraphicsContext currentContext] graphicsPort], return;
border2 = _borderWidth/2,
strokeRect = CGRectMake(bounds.origin.x + border2, var bounds = [self bounds];
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);
CGContextSetFillColor(aContext, [self fillColor]); switch (_boxType)
CGContextSetStrokeColor(aContext, [self borderColor]);
CGContextSetLineWidth(aContext, _borderWidth);
switch(_borderType)
{ {
case CPLineBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES); case CPBoxSeperator:
CGContextStrokeRoundedRectangleInRect(aContext, strokeRect, _cornerRadius, YES, YES, YES, YES); // NSBox does not include a horitontal flag for the seperator type. We have to determine
break; // 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); break;
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;
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 @end
+104 -45
View File
@@ -20,14 +20,17 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import <Foundation/CPIndexSet.j>
@import "CPControl.j" @import "CPControl.j"
@import "CPImage.j" @import "CPImage.j"
@import "CPTableView.j" @import "CPTableView.j"
@import "CPTextField.j"
@import "CPScrollView.j" @import "CPScrollView.j"
/*! /*!
@ingroup appkit @ingroup appkit
@class CPBrowser @class CPBrowser
*/ */
@implementation CPBrowser : CPControl @implementation CPBrowser : CPControl
@@ -64,14 +67,14 @@
+ (CPImage)branchImage + (CPImage)branchImage
{ {
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[self class]] return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
pathForResource:"browser-leaf.png"] pathForResource:"browser-leaf.png"]
size:CGSizeMake(9,9)]; size:CGSizeMake(9,9)];
} }
+ (CPImage)highlightedBranchImage + (CPImage)highlightedBranchImage
{ {
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[self class]] return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
pathForResource:"browser-leaf-highlighted.png"] pathForResource:"browser-leaf-highlighted.png"]
size:CGSizeMake(9,9)]; size:CGSizeMake(9,9)];
} }
@@ -96,18 +99,18 @@
_prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; _prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment]; [_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelected]; [_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelectedDataView];
[_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail]; [_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail];
_horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]]; _horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
[_horizontalScrollView setHasVerticalScroller:NO]; [_horizontalScrollView setHasVerticalScroller:NO];
[_horizontalScrollView setAutohidesScrollers:YES]; [_horizontalScrollView setAutohidesScrollers:YES];
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; [_horizontalScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
_contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))]; _contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))];
[_contentView setAutoresizingMask:CPViewHeightSizable]; [_contentView setAutoresizingMask:CPViewHeightSizable];
[_horizontalScrollView setDocumentView:_contentView]; [_horizontalScrollView setDocumentView:_contentView];
[self addSubview:_horizontalScrollView]; [self addSubview:_horizontalScrollView];
@@ -129,7 +132,7 @@
} }
- (void)setDelegate:(id)anObject - (void)setDelegate:(id)anObject
{ {
_delegate = anObject; _delegate = anObject;
_delegateSupportsImages = [_delegate respondsToSelector:@selector(browser:imageValueForItem:)]; _delegateSupportsImages = [_delegate respondsToSelector:@selector(browser:imageValueForItem:)];
@@ -167,12 +170,10 @@
if (columnIndex >= _tableViews.length) if (columnIndex >= _tableViews.length)
return; return;
var oldValue = _tableViews.length - 1; var oldValue = _tableViews.length - 1,
indexPlusOne = columnIndex + 1; // unloads all later columns.
// unloads all later columns. [[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
var indexPlusOne = columnIndex + 1;
[[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
makeObjectsPerformSelector:@selector(removeFromSuperview)]; makeObjectsPerformSelector:@selector(removeFromSuperview)];
_tableViews = _tableViews.slice(0, indexPlusOne); _tableViews = _tableViews.slice(0, indexPlusOne);
@@ -196,10 +197,10 @@
selectionIndexes = [lastColumn selectedRowIndexes]; selectionIndexes = [lastColumn selectedRowIndexes];
if (lastIndex >= 0 && [selectionIndexes count] > 1) if (lastIndex >= 0 && [selectionIndexes count] > 1)
[CPException raise:CPInvalidArgumentException [CPException raise:CPInvalidArgumentException
reason:"Can't add column, column "+lastIndex+" has invalid selection."]; reason:"Can't add column, column "+lastIndex+" has invalid selection."];
var index = lastIndex+1, var index = lastIndex + 1,
item = index === 0 ? _rootItem : [_tableDelegates[lastIndex] childAtIndex:[selectionIndexes firstIndex]]; item = index === 0 ? _rootItem : [_tableDelegates[lastIndex] childAtIndex:[selectionIndexes firstIndex]];
if (index > 0 && item && [self isLeafItem:item]) if (index > 0 && item && [self isLeafItem:item])
@@ -213,8 +214,6 @@
[table setAllowsEmptySelection:_allowsEmptySelection]; [table setAllowsEmptySelection:_allowsEmptySelection];
[table registerForDraggedTypes:[self registeredDraggedTypes]]; [table registerForDraggedTypes:[self registeredDraggedTypes]];
[self setNextResponder:table];
[self _addTableColumnsToTableView:table forColumnIndex:index]; [self _addTableColumnsToTableView:table forColumnIndex:index];
var delegate = [[_CPBrowserTableDelegate alloc] init]; var delegate = [[_CPBrowserTableDelegate alloc] init];
@@ -233,7 +232,7 @@
[table setAction:@selector(_tableViewClicked:)]; [table setAction:@selector(_tableViewClicked:)];
[table setDoubleAction:@selector(_tableViewDoubleClicked:)]; [table setDoubleAction:@selector(_tableViewDoubleClicked:)];
[table setDraggingDestinationFeedbackStyle:CPTableViewDraggingDestinationFeedbackStyleRegular]; [table setDraggingDestinationFeedbackStyle:CPTableViewDraggingDestinationFeedbackStyleRegular];
var scrollView = [[_CPBrowserScrollView alloc] initWithFrame:CGRectMakeZero()]; var scrollView = [[_CPBrowserScrollView alloc] initWithFrame:CGRectMakeZero()];
[scrollView _setBrowser:self]; [scrollView _setBrowser:self];
[scrollView setDocumentView:table]; [scrollView setDocumentView:table];
@@ -274,10 +273,10 @@
[view setBranchImage:[[self class] branchImage]]; [view setBranchImage:[[self class] branchImage]];
[view setHighlightedBranchImage:[[self class] highlightedBranchImage]]; [view setHighlightedBranchImage:[[self class] highlightedBranchImage]];
[column setDataView:view]; [column setDataView:view];
[column setResizingMask:CPTableColumnNoResizing]; [column setResizingMask:CPTableColumnNoResizing];
[aTableView addTableColumn:column]; [aTableView addTableColumn:column];
} }
@@ -314,6 +313,39 @@
[_contentView setFrameSize:CGSizeMake(xOrigin, height)]; [_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 // ITEMS
- (id)itemAtRow:(int)row inColumn:(int)column - (id)itemAtRow:(int)row inColumn:(int)column
@@ -357,6 +389,10 @@
// CLICK EVENTS // CLICK EVENTS
- (void)trackMouse:(CPEvent)anEvent
{
}
- (void)_column:(unsigned)columnIndex clickedRow:(unsigned)rowIndex - (void)_column:(unsigned)columnIndex clickedRow:(unsigned)rowIndex
{ {
[self setLastColumn:columnIndex]; [self setLastColumn:columnIndex];
@@ -382,6 +418,15 @@
[self sendAction:_doubleAction to:_target]; [self sendAction:_doubleAction to:_target];
} }
- (void)keyDown:(CPEvent)anEvent
{
var column = [self selectedColumn];
if (column === -1)
return;
[_tableViews[column] keyDown:anEvent];
}
// SIZING // SIZING
- (float)columnContentWidthForColumnWidth:(float)aWidth - (float)columnContentWidthForColumnWidth:(float)aWidth
@@ -453,7 +498,7 @@
[_contentView scrollRectToVisible:[[[self tableViewInColumn:columnIndex] enclosingScrollView] frame]]; [_contentView scrollRectToVisible:[[[self tableViewInColumn:columnIndex] enclosingScrollView] frame]];
} }
(void)scrollRowToVisible:(unsigned)rowIndex inColumn:(unsigned)columnIndex - (void)scrollRowToVisible:(unsigned)rowIndex inColumn:(unsigned)columnIndex
{ {
[self scrollColumnToVisible:columnIndex]; [self scrollColumnToVisible:columnIndex];
[[self tableViewInColumn:columnIndex] scrollRowToVisible:rowIndex]; [[self tableViewInColumn:columnIndex] scrollRowToVisible:rowIndex];
@@ -526,6 +571,9 @@
- (CPIndexSet)selectedRowIndexesInColumn:(unsigned)column - (CPIndexSet)selectedRowIndexesInColumn:(unsigned)column
{ {
if (column < 0 || column > [self lastColumn] +1)
return [CPIndexSet indexSet];
return [[self tableViewInColumn:column] selectedRowIndexes]; return [[self tableViewInColumn:column] selectedRowIndexes];
} }
@@ -537,7 +585,7 @@
if ([_delegate respondsToSelector:@selector(browser:selectionIndexesForProposedSelection:inColumn:)]) if ([_delegate respondsToSelector:@selector(browser:selectionIndexesForProposedSelection:inColumn:)])
indexSet = [_delegate browser:self selectionIndexesForProposedSelection:indexSet inColumn:column]; indexSet = [_delegate browser:self selectionIndexesForProposedSelection:indexSet inColumn:column];
if ([_delegate respondsToSelector:@selector(browser:shouldSelectRowIndexes:inColumn:)] && if ([_delegate respondsToSelector:@selector(browser:shouldSelectRowIndexes:inColumn:)] &&
![_delegate browser:self shouldSelectRowIndexes:indexSet inColumn:column]) ![_delegate browser:self shouldSelectRowIndexes:indexSet inColumn:column])
return; return;
@@ -551,8 +599,6 @@
[[self tableViewInColumn:column] selectRowIndexes:indexSet byExtendingSelection:NO]; [[self tableViewInColumn:column] selectRowIndexes:indexSet byExtendingSelection:NO];
[self setNextResponder:[self tableViewInColumn:[self lastColumn]]];
[self scrollColumnToVisible:column]; [self scrollColumnToVisible:column];
if ([_delegate respondsToSelector:@selector(browserSelectionDidChange:)]) if ([_delegate respondsToSelector:@selector(browserSelectionDidChange:)])
@@ -604,6 +650,8 @@
@end @end
var _CPBrowserResizeControlBackgroundImage = nil;
@implementation _CPBrowserResizeControl : CPView @implementation _CPBrowserResizeControl : CPView
{ {
CGPoint _mouseDownX; CGPoint _mouseDownX;
@@ -612,6 +660,26 @@
unsigned _width; 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 - (void)mouseDown:(CPEvent)anEvent
{ {
_mouseDownX = [anEvent locationInWindow].x; _mouseDownX = [anEvent locationInWindow].x;
@@ -626,9 +694,11 @@
[_browser setWidth:_width + deltaX ofColumn:_index]; [_browser setWidth:_width + deltaX ofColumn:_index];
} }
@end - (void)mouseUp:(CPEvent)anEvent
{
}
var _CPBrowserResizeControlBackgroundImage = nil; @end
@implementation _CPBrowserScrollView : CPScrollView @implementation _CPBrowserScrollView : CPScrollView
{ {
@@ -636,24 +706,11 @@ var _CPBrowserResizeControlBackgroundImage = nil;
CPBrowser _browser @accessors; CPBrowser _browser @accessors;
} }
+ (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;
}
- (void)initWithFrame:(CGRect)aFrame - (void)initWithFrame:(CGRect)aFrame
{ {
if (self = [super initWithFrame:aFrame]) if (self = [super initWithFrame:aFrame])
{ {
_resizeControl = [[_CPBrowserResizeControl alloc] initWithFrame:CGRectMakeZero()]; _resizeControl = [[_CPBrowserResizeControl alloc] initWithFrame:CGRectMakeZero()];
[_resizeControl setBackgroundColor:[CPColor colorWithPatternImage:[[self class] backgroundImage]]];
[self addSubview:_resizeControl]; [self addSubview:_resizeControl];
} }
@@ -740,7 +797,7 @@ var _CPBrowserResizeControlBackgroundImage = nil;
} }
- (void)moveLeft:(id)sender - (void)moveLeft:(id)sender
{ {
var previousColumn = [_browser selectedColumn] - 1, var previousColumn = [_browser selectedColumn] - 1,
selectedRow = [_browser selectedRowInColumn:previousColumn]; selectedRow = [_browser selectedRowInColumn:previousColumn];
@@ -748,12 +805,14 @@ var _CPBrowserResizeControlBackgroundImage = nil;
} }
- (void)moveRight:(id)sender - (void)moveRight:(id)sender
{ {
[_browser selectRow:0 inColumn:[_browser selectedColumn] + 1]; [_browser selectRow:0 inColumn:[_browser selectedColumn] + 1];
} }
@end @end
@import <Foundation/CPObject.j>
@implementation _CPBrowserTableDelegate : CPObject @implementation _CPBrowserTableDelegate : CPObject
{ {
CPBrowser _browser @accessors; CPBrowser _browser @accessors;
@@ -804,7 +863,7 @@ var _CPBrowserResizeControlBackgroundImage = nil;
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(int)row proposedDropOperation:(CPTableViewDropOperation)operation - (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(int)row proposedDropOperation:(CPTableViewDropOperation)operation
{ {
if ([_delegate respondsToSelector:@selector(browser:validateDrop:proposedRow:column:dropOperation:)]) if ([_delegate respondsToSelector:@selector(browser:validateDrop:proposedRow:column:dropOperation:)])
[_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation]; return [_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
else else
return CPDragOperationNone; return CPDragOperationNone;
} }
@@ -865,9 +924,9 @@ var _CPBrowserResizeControlBackgroundImage = nil;
{ {
var imageView = [self layoutEphemeralSubviewNamed:@"image-view" var imageView = [self layoutEphemeralSubviewNamed:@"image-view"
positioned:CPWindowAbove positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:nil]; relativeToEphemeralSubviewNamed:nil],
isHighlighted = [self themeState] & CPThemeStateSelectedDataView;
var isHighlighted = [self themeState] & CPThemeStateSelected;
[imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil]; [imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil];
[imageView setImageScaling:CPScaleNone]; [imageView setImageScaling:CPScaleNone];
} }
+174 -69
View File
@@ -26,8 +26,6 @@
@import "CPControl.j" @import "CPControl.j"
@import "CPStringDrawing.j" @import "CPStringDrawing.j"
#include "CoreGraphics/CGGeometry.h"
/* @group CPBezelStyle */ /* @group CPBezelStyle */
@@ -74,7 +72,10 @@ CPChangeBackgroundCellMask = CPBackgroundButtonMask;
CPButtonStateMixed = CPThemeState("mixed"); CPButtonStateMixed = CPThemeState("mixed");
/*! CPButtonDefaultHeight = 24.0;
CPButtonImageOffset = 3.0;
/*!
@ingroup appkit @ingroup appkit
@class CPButton @class CPButton
@@ -85,12 +86,9 @@ CPButtonStateMixed = CPThemeState("mixed");
@implementation CPButton : CPControl @implementation CPButton : CPControl
{ {
BOOL _allowsMixedState; BOOL _allowsMixedState;
CPString _title; CPString _title;
CPString _alternateTitle; CPString _alternateTitle;
CPImage _image;
CPImage _alternateImage;
CPInteger _showsStateBy; CPInteger _showsStateBy;
CPInteger _highlightsBy; CPInteger _highlightsBy;
@@ -99,6 +97,9 @@ CPButtonStateMixed = CPThemeState("mixed");
// NS-style Display Properties // NS-style Display Properties
CPBezelStyle _bezelStyle; CPBezelStyle _bezelStyle;
CPControlSize _controlSize; CPControlSize _controlSize;
CPString _keyEquivalent;
unsigned _keyEquivalentModifierMask;
} }
+ (id)buttonWithTitle:(CPString)aTitle + (id)buttonWithTitle:(CPString)aTitle
@@ -117,21 +118,21 @@ CPButtonStateMixed = CPThemeState("mixed");
return button; return button;
} }
+ (CPString)themeClass + (CPString)defaultThemeClass
{ {
return @"button"; return @"button";
} }
+ (id)themeAttributes + (id)themeAttributes
{ {
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]] return [CPDictionary dictionaryWithObjects:[[CPNull null], 0.0, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]]; forKeys:[@"image", @"image-offset", @"bezel-inset", @"content-inset", @"bezel-color"]];
} }
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
// Should we instead override the defaults? // Should we instead override the defaults?
@@ -139,13 +140,16 @@ CPButtonStateMixed = CPThemeState("mixed");
[self setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"]; [self setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
[self setValue:CPImageLeft forThemeAttribute:@"image-position"]; [self setValue:CPImageLeft forThemeAttribute:@"image-position"];
[self setValue:CPScaleNone forThemeAttribute:@"image-scaling"]; [self setValue:CPScaleNone forThemeAttribute:@"image-scaling"];
_controlSize = CPRegularControlSize; _controlSize = CPRegularControlSize;
_keyEquivalent = @"";
_keyEquivalentModifierMask = 0;
// [self setBezelStyle:CPRoundRectBezelStyle]; // [self setBezelStyle:CPRoundRectBezelStyle];
[self setBordered:YES]; [self setBordered:YES];
} }
return self; return self;
} }
@@ -248,9 +252,9 @@ CPButtonStateMixed = CPThemeState("mixed");
{ {
if (_title === aTitle) if (_title === aTitle)
return; return;
_title = aTitle; _title = aTitle;
[self setNeedsLayout]; [self setNeedsLayout];
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
} }
@@ -264,7 +268,7 @@ CPButtonStateMixed = CPThemeState("mixed");
{ {
if (_alternateTitle === aTitle) if (_alternateTitle === aTitle)
return; return;
_alternateTitle = aTitle; _alternateTitle = aTitle;
[self setNeedsLayout]; [self setNeedsLayout];
@@ -278,18 +282,12 @@ CPButtonStateMixed = CPThemeState("mixed");
- (void)setImage:(CPImage)anImage - (void)setImage:(CPImage)anImage
{ {
if (_image === anImage) [self setValue:anImage forThemeAttribute:@"image"];
return;
_image = anImage;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
} }
- (CPImage)image - (CPImage)image
{ {
return _image; return [self valueForThemeAttribute:@"image" inState:CPThemeStateNormal];
} }
/*! /*!
@@ -298,13 +296,7 @@ CPButtonStateMixed = CPThemeState("mixed");
*/ */
- (void)setAlternateImage:(CPImage)anImage - (void)setAlternateImage:(CPImage)anImage
{ {
if (_alternateImage === anImage) [self setValue:anImage forThemeAttribute:@"image" inState:CPThemeStateHighlighted];
return;
_alternateImage = anImage;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
} }
/*! /*!
@@ -312,7 +304,17 @@ CPButtonStateMixed = CPThemeState("mixed");
*/ */
- (CPImage)alternateImage - (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 - (void)setShowsStateBy:(CPInteger)aMask
@@ -373,13 +375,13 @@ CPButtonStateMixed = CPThemeState("mixed");
[self setShowsStateBy:CPContentsCellMask]; [self setShowsStateBy:CPContentsCellMask];
break; 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."]; 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."]; 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."]; reason:"Unknown button type."];
} }
@@ -395,7 +397,7 @@ CPButtonStateMixed = CPThemeState("mixed");
_imageDimsWhenDisabled = imageShouldDimWhenDisabled; _imageDimsWhenDisabled = imageShouldDimWhenDisabled;
if (_imageDimsWhenDisabled) if ([self hasThemeState:CPThemeStateDisabled])
{ {
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
[self setNeedsLayout]; [self setNeedsLayout];
@@ -410,7 +412,7 @@ CPButtonStateMixed = CPThemeState("mixed");
- (BOOL)startTrackingAt:(CGPoint)aPoint - (BOOL)startTrackingAt:(CGPoint)aPoint
{ {
[self highlight:YES]; [self highlight:YES];
return [super startTrackingAt:aPoint]; return [super startTrackingAt:aPoint];
} }
@@ -431,11 +433,12 @@ CPButtonStateMixed = CPThemeState("mixed");
if (_CGInsetIsEmpty(contentInset)) if (_CGInsetIsEmpty(contentInset))
return bounds; return bounds;
bounds = _CGRectMakeCopy(bounds);
bounds.origin.x += contentInset.left; bounds.origin.x += contentInset.left;
bounds.origin.y += contentInset.top; bounds.origin.y += contentInset.top;
bounds.size.width -= contentInset.left + contentInset.right; bounds.size.width -= contentInset.left + contentInset.right;
bounds.size.height -= contentInset.top + contentInset.bottom; bounds.size.height -= contentInset.top + contentInset.bottom;
return bounds; return bounds;
} }
@@ -449,6 +452,7 @@ CPButtonStateMixed = CPThemeState("mixed");
if (_CGInsetIsEmpty(bezelInset)) if (_CGInsetIsEmpty(bezelInset))
return bounds; return bounds;
bounds = _CGRectMakeCopy(bounds);
bounds.origin.x += bezelInset.left; bounds.origin.x += bezelInset.left;
bounds.origin.y += bezelInset.top; bounds.origin.y += bezelInset.top;
bounds.size.width -= bezelInset.left + bezelInset.right; bounds.size.width -= bezelInset.left + bezelInset.right;
@@ -462,8 +466,20 @@ CPButtonStateMixed = CPThemeState("mixed");
*/ */
- (void)sizeToFit - (void)sizeToFit
{ {
var size = [([self title] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]], [self layoutSubviews];
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
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"], minSize = [self currentValueForThemeAttribute:@"min-size"],
maxSize = [self currentValueForThemeAttribute:@"max-size"]; maxSize = [self currentValueForThemeAttribute:@"max-size"];
@@ -483,10 +499,10 @@ CPButtonStateMixed = CPThemeState("mixed");
{ {
if (aName === "bezel-view") if (aName === "bezel-view")
return [self bezelRectForBounds:[self bounds]]; return [self bezelRectForBounds:[self bounds]];
else if (aName === "content-view") else if (aName === "content-view")
return [self contentRectForBounds:[self bounds]]; return [self contentRectForBounds:[self bounds]];
return [super rectForEphemeralSubviewNamed:aName]; return [super rectForEphemeralSubviewNamed:aName];
} }
@@ -497,7 +513,7 @@ CPButtonStateMixed = CPThemeState("mixed");
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()]; var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO]; [view setHitTests:NO];
return view; return view;
} }
else else
@@ -519,7 +535,8 @@ CPButtonStateMixed = CPThemeState("mixed");
if (contentView) if (contentView)
{ {
[contentView setText:([self hasThemeState:CPThemeStateHighlighted] && _alternateTitle) ? _alternateTitle : _title]; [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 setFont:[self currentValueForThemeAttribute:@"font"]];
[contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]]; [contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
@@ -530,17 +547,10 @@ CPButtonStateMixed = CPThemeState("mixed");
[contentView setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]]; [contentView setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
[contentView setImagePosition:[self currentValueForThemeAttribute:@"image-position"]]; [contentView setImagePosition:[self currentValueForThemeAttribute:@"image-position"]];
[contentView setImageScaling:[self currentValueForThemeAttribute:@"image-scaling"]]; [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 - (void)setBordered:(BOOL)shouldBeBordered
{ {
if (shouldBeBordered) if (shouldBeBordered)
@@ -554,6 +564,79 @@ CPButtonStateMixed = CPThemeState("mixed");
return [self hasThemeState:CPThemeStateBordered]; 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 @end
@implementation CPButton (NS) @implementation CPButton (NS)
@@ -569,11 +652,16 @@ CPButtonStateMixed = CPThemeState("mixed");
@end @end
var CPButtonImageKey = @"CPButtonImageKey", var CPButtonImageKey = @"CPButtonImageKey",
CPButtonAlternateImageKey = @"CPButtonAlternateImageKey", CPButtonAlternateImageKey = @"CPButtonAlternateImageKey",
CPButtonTitleKey = @"CPButtonTitleKey", CPButtonTitleKey = @"CPButtonTitleKey",
CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey", CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey",
CPButtonIsBorderedKey = @"CPButtonIsBorderedKey"; CPButtonIsBorderedKey = @"CPButtonIsBorderedKey",
CPButtonAllowsMixedStateKey = @"CPButtonAllowsMixedStateKey",
CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey",
CPButtonImagePositionKey = @"CPButtonImagePositionKey",
CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey",
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey";
@implementation CPButton (CPCoding) @implementation CPButton (CPCoding)
@@ -584,21 +672,31 @@ var CPButtonImageKey = @"CPButtonImageKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super initWithCoder:aCoder]; self = [super initWithCoder:aCoder];
if (self) if (self)
{ {
_controlSize = CPRegularControlSize; _controlSize = CPRegularControlSize;
[self setImage:[aCoder decodeObjectForKey:CPButtonImageKey]]; _title = [aCoder decodeObjectForKey:CPButtonTitleKey];
[self setAlternateImage:[aCoder decodeObjectForKey:CPButtonAlternateImageKey]]; _alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
[self setTitle:[aCoder decodeObjectForKey:CPButtonTitleKey]]; if ([aCoder containsValueForKey:CPButtonAllowsMixedStateKey])
[self setAlternateTitle:[aCoder decodeObjectForKey:CPButtonAlternateTitleKey]]; _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 setNeedsLayout];
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
} }
return self; return self;
} }
@@ -610,11 +708,18 @@ var CPButtonImageKey = @"CPButtonImageKey",
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeObject:_image forKey:CPButtonImageKey];
[aCoder encodeObject:_alternateImage forKey:CPButtonAlternateImageKey];
[aCoder encodeObject:_title forKey:CPButtonTitleKey]; [aCoder encodeObject:_title forKey:CPButtonTitleKey];
[aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey]; [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 @end
+57 -29
View File
@@ -1,7 +1,5 @@
@import <AppKit/CPView.j> @import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
@implementation CPButtonBar : CPView @implementation CPButtonBar : CPView
@@ -14,8 +12,9 @@
+ (id)plusButton + (id)plusButton
{ {
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)], var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:self] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)]; image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)];
[button setBordered:NO];
[button setImage:image]; [button setImage:image];
[button setImagePosition:CPImageOnly]; [button setImagePosition:CPImageOnly];
@@ -25,23 +24,39 @@
+ (id)minusButton + (id)minusButton
{ {
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)], var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:self] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)]; image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
[button setBordered:NO];
[button setImage:image]; [button setImage:image];
[button setImagePosition:CPImageOnly]; [button setImagePosition:CPImageOnly];
return button; return button;
} }
+ (CPString)themeClass + (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"; return @"button-bar";
} }
+ (id)themeAttributes + (id)themeAttributes
{ {
return [CPDictionary dictionaryWithObjects:[CGInsetMake(0.0, 0.0, 0.0, 0.0), CGSizeMakeZero(), [CPNull null], [CPNull null], [CPNull null]] 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"]]; forKeys:[@"resize-control-inset", @"resize-control-size", @"resize-control-color", @"bezel-color", @"button-bezel-color", @"button-text-color"]];
} }
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
@@ -82,25 +97,8 @@
_buttons = [CPArray arrayWithArray:buttons]; _buttons = [CPArray arrayWithArray:buttons];
for (var i = 0, count = [_buttons count]; i < count; i++) for (var i = 0, count = [_buttons count]; i < count; i++)
{ [_buttons[i] setBordered:YES];
var button = _buttons[i];
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];
[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];
// 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];
[button setBordered:YES];
}
[self setNeedsLayout]; [self setNeedsLayout];
} }
@@ -176,6 +174,11 @@
{ {
[self 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], var buttonsNotHidden = [CPArray arrayWithArray:_buttons],
count = [buttonsNotHidden count]; count = [buttonsNotHidden count];
@@ -184,13 +187,23 @@
[buttonsNotHidden removeObject:buttonsNotHidden[count]]; [buttonsNotHidden removeObject:buttonsNotHidden[count]];
var currentButtonOffset = _resizeControlIsLeftAligned ? CGRectGetMaxX([self bounds]) + 1 : -1, var currentButtonOffset = _resizeControlIsLeftAligned ? CGRectGetMaxX([self bounds]) + 1 : -1,
height = CGRectGetHeight([self bounds]) - 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++) for (var i = 0, count = [buttonsNotHidden count]; i < count; i++)
{ {
var button = buttonsNotHidden[i], var button = buttonsNotHidden[i],
width = CGRectGetWidth([button frame]); width = CGRectGetWidth([button frame]);
if (availableWidth > width)
availableWidth -= width;
else
break;
if (_resizeControlIsLeftAligned) if (_resizeControlIsLeftAligned)
{ {
[button setFrame:CGRectMake(currentButtonOffset - width, 1, width, height)]; [button setFrame:CGRectMake(currentButtonOffset - width, 1, width, height)];
@@ -202,6 +215,16 @@
currentButtonOffset += width - 1; 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]; [self addSubview:button];
} }
@@ -216,6 +239,12 @@
} }
} }
- (void)setFrameSize:(CGSize)aSize
{
[super setFrameSize:aSize];
[self setNeedsLayout];
}
@end @end
var CPButtonBarHasResizeControlKey = @"CPButtonBarHasResizeControlKey", var CPButtonBarHasResizeControlKey = @"CPButtonBarHasResizeControlKey",
@@ -246,4 +275,3 @@ var CPButtonBarHasResizeControlKey = @"CPButtonBarHasResizeControlKey",
} }
@end @end
+27 -2
View File
@@ -23,6 +23,8 @@
@import "CPButton.j" @import "CPButton.j"
CPCheckBoxImageOffset = 4.0;
@implementation CPCheckBox : CPButton @implementation CPCheckBox : CPButton
{ {
} }
@@ -37,7 +39,7 @@
return [self buttonWithTitle:aTitle]; return [self buttonWithTitle:aTitle];
} }
+ (CPString)themeClass + (CPString)defaultThemeClass
{ {
return @"check-box"; return @"check-box";
} }
@@ -55,10 +57,33 @@
[self setImagePosition:CPImageLeft]; [self setImagePosition:CPImageLeft];
[self setAlignment:CPLeftTextAlignment]; [self setAlignment:CPLeftTextAlignment];
[self setBordered:YES]; [self setBordered:NO];
} }
return self; 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 @end
+51 -31
View File
@@ -22,14 +22,12 @@
@import "CPView.j" @import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
/*!
/*!
@ingroup appkit @ingroup appkit
@class CPClipView @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. It is used to hold the document view in a CPScrollView.
*/ */
@implementation CPClipView : CPView @implementation CPClipView : CPView
@@ -47,7 +45,7 @@
return; return;
var defaultCenter = [CPNotificationCenter defaultCenter]; var defaultCenter = [CPNotificationCenter defaultCenter];
if (_documentView) if (_documentView)
{ {
[defaultCenter [defaultCenter
@@ -59,29 +57,29 @@
removeObserver:self removeObserver:self
name:CPViewBoundsDidChangeNotification name:CPViewBoundsDidChangeNotification
object:_documentView]; object:_documentView];
[_documentView removeFromSuperview]; [_documentView removeFromSuperview];
} }
_documentView = aView; _documentView = aView;
if (_documentView) if (_documentView)
{ {
[self addSubview:_documentView]; [self addSubview:_documentView];
[_documentView setPostsFrameChangedNotifications:YES];
[_documentView setPostsBoundsChangedNotifications:YES];
[defaultCenter [_documentView setPostsFrameChangedNotifications:YES];
[_documentView setPostsBoundsChangedNotifications:YES];
[defaultCenter
addObserver:self addObserver:self
selector:@selector(viewFrameChanged:) selector:@selector(viewFrameChanged:)
name:CPViewFrameDidChangeNotification name:CPViewFrameDidChangeNotification
object:_documentView]; object:_documentView];
[defaultCenter [defaultCenter
addObserver:self addObserver:self
selector:@selector(viewBoundsChanged:) selector:@selector(viewBoundsChanged:)
name:CPViewBoundsDidChangeNotification name:CPViewBoundsDidChangeNotification
object:_documentView]; object:_documentView];
} }
} }
@@ -106,7 +104,7 @@
return _CGPointMakeZero(); return _CGPointMakeZero();
var documentFrame = [_documentView frame]; var documentFrame = [_documentView frame];
aPoint.x = MAX(0.0, MIN(aPoint.x, MAX(_CGRectGetWidth(documentFrame) - _CGRectGetWidth(_bounds), 0.0))); 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))); aPoint.y = MAX(0.0, MIN(aPoint.y, MAX(_CGRectGetHeight(documentFrame) - _CGRectGetHeight(_bounds), 0.0)));
@@ -117,7 +115,7 @@
{ {
if (_CGPointEqualToPoint(_bounds.origin, aPoint)) if (_CGPointEqualToPoint(_bounds.origin, aPoint))
return; return;
[super setBoundsOrigin:aPoint]; [super setBoundsOrigin:aPoint];
var superview = [self superview], var superview = [self superview],
@@ -126,7 +124,7 @@
// FIXME: Should CPScrollView be finding out about this on its own somehow? // FIXME: Should CPScrollView be finding out about this on its own somehow?
scrollViewClass = objj_getClass("CPScrollView"); scrollViewClass = objj_getClass("CPScrollView");
if([superview isKindOfClass:scrollViewClass]) if ([superview isKindOfClass:scrollViewClass])
[superview reflectScrolledClipView:self]; [superview reflectScrolledClipView:self];
} }
@@ -166,12 +164,12 @@
- (void)_constrainScrollPoint - (void)_constrainScrollPoint
{ {
var oldScrollPoint = [self bounds].origin; 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. // sense given the new frame of the document view.
[self scrollToPoint:oldScrollPoint]; [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). // the scroll points are not equal (meaning scrollToPoint: didn't early bail).
if (!CGPointEqualToPoint(oldScrollPoint, [self bounds].origin)) if (!CGPointEqualToPoint(oldScrollPoint, [self bounds].origin))
return; return;
@@ -187,20 +185,42 @@
[superview reflectScrolledClipView:self]; [superview reflectScrolledClipView:self];
} }
- (BOOL)autoscroll:(CPEvent)anEvent - (BOOL)autoscroll:(CPEvent)anEvent
{ {
var bounds = [self bounds], 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; 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; if (![superview isKindOfClass:[CPScrollView class]] || [superview hasHorizontalScroller])
newRect.size = CPSizeMake(10, 10); {
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 @end
@@ -214,14 +234,14 @@ var CPClipViewDocumentViewKey = @"CPScrollViewDocumentView";
{ {
if (self = [super initWithCoder:aCoder]) if (self = [super initWithCoder:aCoder])
[self setDocumentView:[aCoder decodeObjectForKey:CPClipViewDocumentViewKey]]; [self setDocumentView:[aCoder decodeObjectForKey:CPClipViewDocumentViewKey]];
return self; return self;
} }
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeObject:_documentView forKey:CPClipViewDocumentViewKey]; [aCoder encodeObject:_documentView forKey:CPClipViewDocumentViewKey];
} }
+196 -100
View File
@@ -30,16 +30,16 @@
@import "CPCollectionViewItem.j" @import "CPCollectionViewItem.j"
/*! /*!
@ingroup appkit @ingroup appkit
@class CPCollectionView @class CPCollectionView
This class displays an array as a grid of objects, where each object is represented by a view. 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 The view is controlled by creating a CPCollectionViewItem and specifying its view, then
setting that item as the collection view prototype. setting that item as the collection view prototype.
@par Delegate Methods @par Delegate Methods
@delegate -(void)collectionViewDidChangeSelection:(CPCollectionView)collectionView; @delegate -(void)collectionViewDidChangeSelection:(CPCollectionView)collectionView;
Called when the selection in the collection view has changed. Called when the selection in the collection view has changed.
@param collectionView the collection view who's selection changed @param collectionView the collection view who's selection changed
@@ -67,35 +67,35 @@
{ {
CPArray _content; CPArray _content;
CPArray _items; CPArray _items;
CPData _itemData; CPData _itemData;
CPCollectionViewItem _itemPrototype; CPCollectionViewItem _itemPrototype;
CPCollectionViewItem _itemForDragging; CPCollectionViewItem _itemForDragging;
CPMutableArray _cachedItems; CPMutableArray _cachedItems;
unsigned _maxNumberOfRows; unsigned _maxNumberOfRows;
unsigned _maxNumberOfColumns; unsigned _maxNumberOfColumns;
CGSize _minItemSize; CGSize _minItemSize;
CGSize _maxItemSize; CGSize _maxItemSize;
CPArray _backgroundColors; CPArray _backgroundColors;
float _tileWidth; float _tileWidth;
BOOL _isSelectable; BOOL _isSelectable;
BOOL _allowsMultipleSelection; BOOL _allowsMultipleSelection;
BOOL _allowsEmptySelection; BOOL _allowsEmptySelection;
CPIndexSet _selectionIndexes; CPIndexSet _selectionIndexes;
CGSize _itemSize; CGSize _itemSize;
float _horizontalMargin; float _horizontalMargin;
float _verticalMargin; float _verticalMargin;
unsigned _numberOfRows; unsigned _numberOfRows;
unsigned _numberOfColumns; unsigned _numberOfColumns;
id _delegate; id _delegate;
CPEvent _mouseDownEvent; CPEvent _mouseDownEvent;
@@ -104,14 +104,14 @@
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
_items = []; _items = [];
_content = []; _content = [];
_cachedItems = []; _cachedItems = [];
_itemSize = CGSizeMakeZero(); _itemSize = CGSizeMakeZero();
_minItemSize = CGSizeMakeZero(); _minItemSize = CGSizeMakeZero();
_maxItemSize = CGSizeMakeZero(); _maxItemSize = CGSizeMakeZero();
@@ -120,12 +120,12 @@
_verticalMargin = 5.0; _verticalMargin = 5.0;
_tileWidth = -1.0; _tileWidth = -1.0;
_selectionIndexes = [CPIndexSet indexSet]; _selectionIndexes = [CPIndexSet indexSet];
_allowsEmptySelection = YES; _allowsEmptySelection = YES;
_isSelectable = YES; _isSelectable = YES;
} }
return self; return self;
} }
@@ -196,8 +196,8 @@
// Setting the Content // Setting the Content
/*! /*!
Sets the content of the collection view to the content in \c anArray. 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. 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. It's the responsibility of your custom collection view item to interpret the object.
@param anArray the content array @param anArray the content array
*/ */
@@ -205,9 +205,9 @@
{ {
if (_content == anArray) if (_content == anArray)
return; return;
_content = anArray; _content = anArray;
[self reloadContent]; [self reloadContent];
} }
@@ -236,13 +236,13 @@
{ {
if (_isSelectable == isSelectable) if (_isSelectable == isSelectable)
return; return;
_isSelectable = isSelectable; _isSelectable = isSelectable;
if (!_isSelectable) if (!_isSelectable)
{ {
var index = CPNotFound; var index = CPNotFound;
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound) while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:NO]; [_items[index] setSelected:NO];
} }
@@ -297,23 +297,25 @@
*/ */
- (void)setSelectionIndexes:(CPIndexSet)anIndexSet - (void)setSelectionIndexes:(CPIndexSet)anIndexSet
{ {
if (_selectionIndexes == anIndexSet || !_isSelectable) if ([_selectionIndexes isEqual:anIndexSet] || !_isSelectable)
return; return;
var index = CPNotFound; var index = CPNotFound;
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound) while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:NO]; [_items[index] setSelected:NO];
_selectionIndexes = anIndexSet; _selectionIndexes = anIndexSet;
var index = CPNotFound; var index = CPNotFound;
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound) while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:YES]; [_items[index] setSelected:YES];
[[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)]) if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)])
[_delegate collectionViewDidChangeSelection:self] [_delegate collectionViewDidChangeSelection:self];
} }
/*! /*!
@@ -326,10 +328,10 @@
/* @ignore */ /* @ignore */
- (void)reloadContent - (void)reloadContent
{ {
// Remove current views // Remove current views
var count = _items.length; var count = _items.length;
while (count--) while (count--)
{ {
[[_items[count] view] removeFromSuperview]; [[_items[count] view] removeFromSuperview];
@@ -337,7 +339,7 @@
_cachedItems.push(_items[count]); _cachedItems.push(_items[count]);
} }
_items = []; _items = [];
if (!_itemPrototype || !_content) if (!_itemPrototype || !_content)
@@ -350,7 +352,7 @@
for (; index < count; ++index) for (; index < count; ++index)
{ {
_items.push([self newItemForRepresentedObject:_content[index]]); _items.push([self newItemForRepresentedObject:_content[index]]);
[self addSubview:[_items[index] view]]; [self addSubview:[_items[index] view]];
} }
@@ -365,49 +367,49 @@
- (void)tile - (void)tile
{ {
var width = CGRectGetWidth([self bounds]); var width = CGRectGetWidth([self bounds]);
if (![_content count] || width == _tileWidth) if (![_content count] || width == _tileWidth)
return; 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 // either proportioned out to the views (if their minSize != maxSize) or used as
// margin // margin
var itemSize = CGSizeMakeCopy(_minItemSize); var itemSize = CGSizeMakeCopy(_minItemSize);
_numberOfColumns = MAX(1.0, FLOOR(width / itemSize.width)); _numberOfColumns = MAX(1.0, FLOOR(width / itemSize.width));
if (_maxNumberOfColumns > 0) if (_maxNumberOfColumns > 0)
_numberOfColumns = MIN(_maxNumberOfColumns, _numberOfColumns); _numberOfColumns = MIN(_maxNumberOfColumns, _numberOfColumns);
var remaining = width - _numberOfColumns * itemSize.width, var remaining = width - _numberOfColumns * itemSize.width,
itemsNeedSizeUpdate = NO; itemsNeedSizeUpdate = NO;
if (remaining > 0 && itemSize.width < _maxItemSize.width) if (remaining > 0 && itemSize.width < _maxItemSize.width)
itemSize.width = MIN(_maxItemSize.width, itemSize.width + FLOOR(remaining / _numberOfColumns)); 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. // 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) if (_maxNumberOfColumns == 1 && itemSize.width < _maxItemSize.width && itemSize.width < width)
itemSize.width = MIN(_maxItemSize.width, width); itemSize.width = MIN(_maxItemSize.width, width);
if (!CGSizeEqualToSize(_itemSize, itemSize)) if (!CGSizeEqualToSize(_itemSize, itemSize))
{ {
_itemSize = itemSize; _itemSize = itemSize;
itemsNeedSizeUpdate = YES; itemsNeedSizeUpdate = YES;
} }
var index = 0, var index = 0,
count = _items.length; count = _items.length;
if (_maxNumberOfColumns > 0 && _maxNumberOfRows > 0) if (_maxNumberOfColumns > 0 && _maxNumberOfRows > 0)
count = MIN(count, _maxNumberOfColumns * _maxNumberOfRows); count = MIN(count, _maxNumberOfColumns * _maxNumberOfRows);
_numberOfRows = CEIL(count / _numberOfColumns); _numberOfRows = CEIL(count / _numberOfColumns);
_horizontalMargin = FLOOR((width - _numberOfColumns * itemSize.width) / (_numberOfColumns + 1)); _horizontalMargin = FLOOR((width - _numberOfColumns * itemSize.width) / (_numberOfColumns + 1));
var x = _horizontalMargin, var x = _horizontalMargin,
y = -itemSize.height; y = -itemSize.height;
for (; index < count; ++index) for (; index < count; ++index)
{ {
if (index % _numberOfColumns == 0) if (index % _numberOfColumns == 0)
@@ -415,19 +417,28 @@
x = _horizontalMargin; x = _horizontalMargin;
y += _verticalMargin + itemSize.height; y += _verticalMargin + itemSize.height;
} }
var view = [_items[index] view]; var view = [_items[index] view];
[view setFrameOrigin:CGPointMake(x, y)]; [view setFrameOrigin:CGPointMake(x, y)];
if (itemsNeedSizeUpdate) if (itemsNeedSizeUpdate)
[view setFrameSize:_itemSize]; [view setFrameSize:_itemSize];
x += itemSize.width + _horizontalMargin; 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; _tileWidth = width;
[self setFrameSize:CGSizeMake(width, y + itemSize.height + _verticalMargin)]; [self setFrameSize:CGSizeMake(width, proposedHeight)];
_tileWidth = -1.0; _tileWidth = -1.0;
} }
@@ -445,9 +456,9 @@
{ {
if (_maxNumberOfRows == aMaxNumberOfRows) if (_maxNumberOfRows == aMaxNumberOfRows)
return; return;
_maxNumberOfRows = aMaxNumberOfRows; _maxNumberOfRows = aMaxNumberOfRows;
[self tile]; [self tile];
} }
@@ -467,9 +478,9 @@
{ {
if (_maxNumberOfColumns == aMaxNumberOfColumns) if (_maxNumberOfColumns == aMaxNumberOfColumns)
return; return;
_maxNumberOfColumns = aMaxNumberOfColumns; _maxNumberOfColumns = aMaxNumberOfColumns;
[self tile]; [self tile];
} }
@@ -506,9 +517,9 @@
{ {
if (CGSizeEqualToSize(_minItemSize, aSize)) if (CGSizeEqualToSize(_minItemSize, aSize))
return; return;
_minItemSize = CGSizeMakeCopy(aSize); _minItemSize = CGSizeMakeCopy(aSize);
[self tile]; [self tile];
} }
@@ -528,9 +539,9 @@
{ {
if (CGSizeEqualToSize(_maxItemSize, aSize)) if (CGSizeEqualToSize(_maxItemSize, aSize))
return; return;
_maxItemSize = CGSizeMakeCopy(aSize); _maxItemSize = CGSizeMakeCopy(aSize);
[self tile]; [self tile];
} }
@@ -582,14 +593,51 @@
index = row * _numberOfColumns + column; index = row * _numberOfColumns + column;
if (index >= 0 && index < _items.length) 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) else if (_allowsEmptySelection)
[self setSelectionIndexes:[CPIndexSet indexSet]]; [self setSelectionIndexes:[CPIndexSet indexSet]];
} }
- (void)mouseDragged:(CPEvent)anEvent - (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:)]) if (![_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)])
return; return;
@@ -606,8 +654,6 @@
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self]; [[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self];
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if (!_itemForDragging) if (!_itemForDragging)
_itemForDragging = [self newItemForRepresentedObject:_content[[_selectionIndexes firstIndex]]]; _itemForDragging = [self newItemForRepresentedObject:_content[[_selectionIndexes firstIndex]]];
else else
@@ -648,9 +694,9 @@
{ {
if (_verticalMargin == aVerticalMargin) if (_verticalMargin == aVerticalMargin)
return; return;
_verticalMargin = aVerticalMargin; _verticalMargin = aVerticalMargin;
[self tile]; [self tile];
} }
@@ -701,7 +747,7 @@
count = [indexArray count]; count = [indexArray count];
for (; index < count; ++index) for (; index < count; ++index)
frame = CGRectUnion(frame, [self rectForItemAtIndex:indexArray[index]]); frame = CGRectUnion(frame, [self frameForItemAtIndex:indexArray[index]]);
return frame; return frame;
} }
@@ -710,6 +756,29 @@
@implementation CPCollectionView (KeyboardInteraction) @implementation CPCollectionView (KeyboardInteraction)
- (void)_modifySelectionWithNewIndex:(int)anIndex direction:(int)aDirection expand:(BOOL)shouldExpand
{
anIndex = MIN(MAX(anIndex, 0), [[self items] count] - 1);
if (_allowsMultipleSelection && shouldExpand)
{
var indexes = [_selectionIndexes copy],
bottomAnchor = [indexes firstIndex],
topAnchor = [indexes lastIndex];
// 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 - (void)_scrollToSelection
{ {
var frame = [self frameForItemsAtIndexes:[self selectionIndexes]]; var frame = [self frameForItemsAtIndexes:[self selectionIndexes]];
@@ -721,41 +790,57 @@
- (void)moveLeft:(id)sender - (void)moveLeft:(id)sender
{ {
var index = [[self selectionIndexes] firstIndex]; var index = [[self selectionIndexes] firstIndex];
if (index === CPNotFound) if (index === CPNotFound)
index = [[self items] count]; index = [[self items] count];
index = MAX(index - 1, 0); [self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:NO];
}
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]]; - (void)moveLeftAndModifySelection:(id)sender
[self _scrollToSelection]; {
var index = [[self selectionIndexes] firstIndex];
if (index === CPNotFound)
index = [[self items] count];
[self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:YES];
} }
- (void)moveRight:(id)sender - (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]]; - (void)moveRightAndModifySelection:(id)sender
[self _scrollToSelection]; {
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:YES];
} }
- (void)moveDown:(id)sender - (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]]; - (void)moveDownAndModifySelection:(id)sender
[self _scrollToSelection]; {
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:YES];
} }
- (void)moveUp:(id)sender - (void)moveUp:(id)sender
{ {
var index = [[self selectionIndexes] firstIndex]; var index = [[self selectionIndexes] firstIndex];
if (index == CPNotFound) if (index == CPNotFound)
index = [[self items] count]; index = [[self items] count];
index = MAX(0, index - [self numberOfColumns]); [self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:NO];
}
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]]; - (void)moveUpAndModifySelection:(id)sender
[self _scrollToSelection]; {
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 - (void)deleteBackward:(id)sender
@@ -765,8 +850,8 @@
[[self delegate] collectionView:self shouldDeleteItemsAtIndexes:[self selectionIndexes]]; [[self delegate] collectionView:self shouldDeleteItemsAtIndexes:[self selectionIndexes]];
var index = [[self selectionIndexes] firstIndex]; var index = [[self selectionIndexes] firstIndex];
if (index > [[self content] count]-1) if (index > [[self content] count] - 1)
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count]-1]]; [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count] - 1]];
[self _scrollToSelection]; [self _scrollToSelection];
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
@@ -800,11 +885,14 @@
@end @end
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey", var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey", CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey", CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey", CPCollectionViewMaxNumberOfRowsKey = @"CPCollectionViewMaxNumberOfRowsKey",
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey"; CPCollectionViewMaxNumberOfColumnsKey = @"CPCollectionViewMaxNumberOfColumnsKey",
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
CPCollectionViewAllowsMultipleSelectionKey = @"CPCollectionViewAllowsMultipleSelectionKey",
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
@implementation CPCollectionView (CPCoding) @implementation CPCollectionView (CPCoding)
@@ -821,20 +909,24 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
_cachedItems = []; _cachedItems = [];
_itemSize = CGSizeMakeZero(); _itemSize = CGSizeMakeZero();
_minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero(); _minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero();
_maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero(); _maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero();
_maxNumberOfRows = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfRowsKey] || 0;
_maxNumberOfColumns = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfColumnsKey] || 0;
_verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey]; _verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey];
_isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey]; _isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey];
_allowsMultipleSelection = [aCoder decodeBoolForKey:CPCollectionViewAllowsMultipleSelectionKey];
[self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]]; [self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]];
_tileWidth = -1.0; _tileWidth = -1.0;
_selectionIndexes = [CPIndexSet indexSet]; _selectionIndexes = [CPIndexSet indexSet];
_allowsEmptySelection = YES; _allowsEmptySelection = YES;
} }
@@ -847,12 +939,16 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
if (!CGSizeEqualToSize(_minItemSize, CGSizeMakeZero())) if (!CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
[aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey]; [aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey];
if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero())) if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
[aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey]; [aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
[aCoder encodeInt:_maxNumberOfRows forKey:CPCollectionViewMaxNumberOfRowsKey];
[aCoder encodeInt:_maxNumberOfColumns forKey:CPCollectionViewMaxNumberOfColumnsKey];
[aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey]; [aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey];
[aCoder encodeBool:_allowsMultipleSelection forKey:CPCollectionViewAllowsMultipleSelectionKey];
[aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey]; [aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
[aCoder encodeObject:_backgroundColors forKey:CPCollectionViewBackgroundColorsKey]; [aCoder encodeObject:_backgroundColors forKey:CPCollectionViewBackgroundColorsKey];
+1
View File
@@ -22,6 +22,7 @@
@import "CPViewController.j" @import "CPViewController.j"
/*! /*!
Represents an object inside a CPCollectionView. Represents an object inside a CPCollectionView.
*/ */
+87 -91
View File
@@ -32,7 +32,7 @@ var _redComponent = 0,
_greenComponent = 1, _greenComponent = 1,
_blueComponent = 2, _blueComponent = 2,
_alphaCompnent = 3; _alphaCompnent = 3;
var _hueComponent = 0, var _hueComponent = 0,
_saturationComponent = 1, _saturationComponent = 1,
_brightnessComponent = 2; _brightnessComponent = 2;
@@ -54,27 +54,21 @@ var cachedBlackColor,
cachedShadowColor, cachedShadowColor,
cachedClearColor; cachedClearColor;
/*! /*!
@ingroup appkit @ingroup appkit
@code CPColor
\c CPColor can be used to represent color \c CPColor can be used to represent color
in an RGB or HSB model with an optional transparency value.</p> in an RGB or HSB model with an optional transparency value.</p>
<p>It also provides some class helper methods that <p>It also provides some class helper methods that
returns instances of commonly used colors.</p> 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 @implementation CPColor : CPObject
{ {
CPArray _components; CPArray _components;
CPImage _patternImage; 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 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 the alpha component, a value of 1.0 is opaque, and 0.0 means
completely transparent. completely transparent.
@param red the red component of the color @param red the red component of the color
@param green the green component of the color @param green the green component of the color
@param blue the blue component of the color @param blue the blue component of the color
@param alpha the alpha component @param alpha the alpha component
@return a color initialized to the values specified @return a color initialized to the values specified
*/ */
+ (CPColor)colorWithRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha + (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: @deprecated in favor of colorWithRed:green:blue:alpha:
Creates a color in the RGB color space, with an alpha value. 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 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 the alpha component, a value of 1.0 is opaque, and 0.0 means
completely transparent. completely transparent.
@param red the red component of the color @param red the red component of the color
@param green the green component of the color @param green the green component of the color
@param blue the blue component of the color @param blue the blue component of the color
@param alpha the alpha component @param alpha the alpha component
@return a color initialized to the values specified @return a color initialized to the values specified
*/ */
+ (CPColor)colorWithCalibratedRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha + (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. 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. 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 white a float between 0.0 and 1.0
@param alpha the alpha component 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 @return a color initialized to the values specified
*/ */
+ (CPColor)colorWithWhite:(float)white alpha:(float)alpha + (CPColor)colorWithWhite:(float)white alpha:(float)alpha
@@ -132,13 +126,13 @@ var cachedBlackColor,
/*! /*!
@deprecated in favor of colorWithWhite:apha: @deprecated in favor of colorWithWhite:apha:
Creates a new color object with \c white for the RGB components. 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. 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 white a float between 0.0 and 1.0
@param alpha the alpha component 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 @return a color initialized to the values specified
*/ */
+ (CPColor)colorWithCalibratedWhite:(float)white alpha:(float)alpha + (CPColor)colorWithCalibratedWhite:(float)white alpha:(float)alpha
@@ -148,11 +142,11 @@ var cachedBlackColor,
/*! /*!
Creates a new color in HSB space. Creates a new color in HSB space.
@param hue the hue value @param hue the hue value
@param saturation the saturation value @param saturation the saturation value
@param brightness the brightness value @param brightness the brightness value
@return the initialized color @return the initialized color
*/ */
+ (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness + (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 + (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]; return [CPColor colorWithCalibratedWhite:brightness / 100.0 alpha:alpha];
var f = hue % 60, var f = hue % 60,
p = (brightness * (100 - saturation)) / 10000, p = (brightness * (100 - saturation)) / 10000,
q = (brightness * (6000 - saturation * f)) / 600000, q = (brightness * (6000 - saturation * f)) / 600000,
t = (brightness * (6000 - saturation * (60 -f))) / 600000, t = (brightness * (6000 - saturation * (60 -f))) / 600000,
b = brightness / 100.0; 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 0: return [CPColor colorWithCalibratedRed: b green: t blue: p alpha: alpha];
case 1: return [CPColor colorWithCalibratedRed: q green: b 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, Creates an RGB color from a hexadecimal string. For example,
the a string of "FFFFFF" would return a white CPColor. the a string of "FFFFFF" would return a white CPColor.
"FF0000" would return a pure red, "00FF00" would return a "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 @param hex a 6 character long string of hex
@@ -194,7 +188,8 @@ var cachedBlackColor,
*/ */
+ (CPColor)colorWithHexString:(string)hex + (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)". Creates a CPColor from a valid CSS RGB string. Example, "rgb(32,64,129)".
@param aString a CSS color string @param aString a CSS color string
@return a color initialized to the value in the css string @return a color initialized to the value in the css string
*/ */
@@ -409,23 +404,23 @@ var cachedBlackColor,
/* @ignore */ /* @ignore */
- (id)_initWithCSSString:(CPString)aString - (id)_initWithCSSString:(CPString)aString
{ {
if(aString.indexOf("rgb") == CPNotFound) if (aString.indexOf("rgb") == CPNotFound)
return nil; return nil;
self = [super init]; self = [super init];
var startingIndex = aString.indexOf("("); var startingIndex = aString.indexOf("("),
var parts = aString.substring(startingIndex+1).split(','); parts = aString.substring(startingIndex + 1).split(',');
_components = [ _components = [
parseInt(parts[0], 10) / 255.0, parseInt(parts[0], 10) / 255.0,
parseInt(parts[1], 10) / 255.0, parseInt(parts[1], 10) / 255.0,
parseInt(parts[2], 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; _cssString = aString;
return self; return self;
} }
@@ -433,7 +428,7 @@ var cachedBlackColor,
- (id)_initWithRGBA:(CPArray)components - (id)_initWithRGBA:(CPArray)components
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_components = components; _components = components;
@@ -454,14 +449,14 @@ var cachedBlackColor,
- (id)_initWithPatternImage:(CPImage)anImage - (id)_initWithPatternImage:(CPImage)anImage
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_patternImage = anImage; _patternImage = anImage;
_cssString = "url(\"" + [_patternImage filename] + "\")"; _cssString = "url(\"" + [_patternImage filename] + "\")";
_components = [0.0, 0.0, 0.0, 1.0]; _components = [0.0, 0.0, 0.0, 1.0];
} }
return self; return self;
} }
@@ -523,17 +518,17 @@ var cachedBlackColor,
/*! /*!
Returns a new color with the same RGB as the receiver but a new alpha component. 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 @param anAlphaComponent the alpha component for the new color
@return a new color object @return a new color object
*/ */
- (CPColor)colorWithAlphaComponent:(float)anAlphaComponent - (CPColor)colorWithAlphaComponent:(float)anAlphaComponent
{ {
var components = _components.slice(); var components = _components.slice();
components[components.length - 1] = anAlphaComponent; components[components.length - 1] = anAlphaComponent;
return [[[self class] alloc] _initWithRGBA:components]; return [[[self class] alloc] _initWithRGBA:components];
} }
@@ -552,37 +547,40 @@ var cachedBlackColor,
var red = ROUND(_components[_redComponent] * 255.0), var red = ROUND(_components[_redComponent] * 255.0),
green = ROUND(_components[_greenComponent] * 255.0), green = ROUND(_components[_greenComponent] * 255.0),
blue = ROUND(_components[_blueComponent] * 255.0); blue = ROUND(_components[_blueComponent] * 255.0);
var max = MAX(red, green, blue), var max = MAX(red, green, blue),
min = MIN(red, green, blue), min = MIN(red, green, blue),
delta = max - min; delta = max - min;
var brightness = max / 255.0, var brightness = max / 255.0,
saturation = (max != 0) ? delta / max : 0; saturation = (max != 0) ? delta / max : 0;
var hue; var hue;
if(saturation == 0)
if (saturation == 0)
{
hue = 0; hue = 0;
}
else else
{ {
var rr = (max - red) / delta; var rr = (max - red) / delta,
var gr = (max - green) / delta; gr = (max - green) / delta,
var br = (max - blue) / delta; br = (max - blue) / delta;
if (red == max) if (red == max)
hue = br - gr; hue = br - gr;
else if (green == max) else if (green == max)
hue = 2 + rr - br; hue = 2 + rr - br;
else else
hue = 4 + gr - rr; hue = 4 + gr - rr;
hue /= 6; hue /= 6;
if (hue < 0) if (hue < 0)
hue++; hue++;
} }
return [ return [
ROUND(hue * 360.0), ROUND(hue * 360.0),
ROUND(saturation * 100.0), ROUND(saturation * 100.0),
ROUND(brightness * 100.0) ROUND(brightness * 100.0)
]; ];
@@ -630,7 +628,7 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
@implementation CPColor (CoreGraphicsExtensions) @implementation CPColor (CoreGraphicsExtensions)
/*! /*!
Set's the receiver to be the fill and stroke color in the current graphics context Set's the receiver to be the fill and stroke color in the current graphics context
*/ */
- (void)set - (void)set
@@ -639,16 +637,16 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
[self setStroke]; [self setStroke];
} }
/*! /*!
Set's the receiver to be the fill color in the current graphics context Set's the receiver to be the fill color in the current graphics context
*/ */
- (void)setFill - (void)setFill
{ {
var ctx = [[CPGraphicsContext currentContext] graphicsPort]; 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 Set's the receiver to be the stroke color in the current graphics context
*/ */
- (void)setStroke - (void)setStroke
@@ -681,7 +679,7 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
{ {
if ([aCoder containsValueForKey:CPColorPatternImageKey]) if ([aCoder containsValueForKey:CPColorPatternImageKey])
return [self _initWithPatternImage:[aCoder decodeObjectForKey:CPColorPatternImageKey]]; return [self _initWithPatternImage:[aCoder decodeObjectForKey:CPColorPatternImageKey]];
return [self _initWithRGBA:[aCoder decodeObjectForKey:CPColorComponentsKey]]; return [self _initWithRGBA:[aCoder decodeObjectForKey:CPColorComponentsKey]];
} }
@@ -699,10 +697,8 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
@end @end
var hexCharacters = "0123456789ABCDEF";
// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior var hexCharacters = "0123456789ABCDEF";
var hexToRGB, rgbToHex, byteToHex;
/*! /*!
Used for the CPColor \c +colorWithHexString: implementation Used for the CPColor \c +colorWithHexString: implementation
@@ -710,39 +706,39 @@ var hexToRGB, rgbToHex, byteToHex;
@class CPColor @class CPColor
@return an array of rgb components @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); 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; return null;
hex = hex.toUpperCase(); hex = hex.toUpperCase();
for(var i=0; i<hex.length; i++) for (var i = 0; i < hex.length; i++)
if(hexCharacters.indexOf(hex.charAt(i)) == -1) if (hexCharacters.indexOf(hex.charAt(i)) == -1)
return null; return null;
var red = (hexCharacters.indexOf(hex.charAt(0)) * 16 + hexCharacters.indexOf(hex.charAt(1))) / 255.0; 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; 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; blue = (hexCharacters.indexOf(hex.charAt(4)) * 16 + hexCharacters.indexOf(hex.charAt(5))) / 255.0;
return [red, green, blue, 1.0]; return [red, green, blue, 1.0];
} };
function rgbToHex(r,g,b) { var rgbToHex = function(r,g,b)
{
return byteToHex(r) + byteToHex(g) + byteToHex(b); return byteToHex(r) + byteToHex(g) + byteToHex(b);
} };
function byteToHex(n) { var byteToHex = function(n)
if (!n || isNaN(n)) return "00"; {
n = ROUND(MIN(255,MAX(0,256*n))); if (!n || isNaN(n))
return hexCharacters.charAt((n - n % 16) / 16) + return "00";
hexCharacters.charAt(n % 16);
}
// Toll-Free bridge CPColor to CGColor. n = FLOOR(MIN(255, MAX(0, 256 * n)));
//CGColor.prototype.isa = CPColor;
//[CPColor initialize];
//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 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CPApplication.j"
@import "CPButton.j" @import "CPButton.j"
@import "CPCookie.j" @import "CPCookie.j"
@import "CPPanel.j" @import "CPPanel.j"
@import "CPView.j" @import "CPView.j"
CPColorPanelColorDidChangeNotification = @"CPColorPanelColorDidChangeNotification"; CPColorPanelColorDidChangeNotification = @"CPColorPanelColorDidChangeNotification";
var PREVIEW_HEIGHT = 20.0, var PREVIEW_HEIGHT = 20.0,
@@ -35,7 +37,7 @@ var PREVIEW_HEIGHT = 20.0,
var SharedColorPanel = nil, var SharedColorPanel = nil,
ColorPickerClasses = []; ColorPickerClasses = [];
/* /*
A color wheel A color wheel
@global @global
@@ -52,7 +54,7 @@ CPSliderColorPickerMode = 2;
CPColorPickerViewWidth = 265, CPColorPickerViewWidth = 265,
CPColorPickerViewHeight = 370; CPColorPickerViewHeight = 370;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPColorPanel @class CPColorPanel
@@ -61,7 +63,7 @@ CPColorPickerViewHeight = 370;
obtain the panel, call the \c +sharedColorPanel method. obtain the panel, call the \c +sharedColorPanel method.
*/ */
@implementation CPColorPanel : CPPanel @implementation CPColorPanel : CPPanel
{ {
_CPColorPanelToolbar _toolbar; _CPColorPanelToolbar _toolbar;
_CPColorPanelSwatches _swatchView; _CPColorPanelSwatches _swatchView;
_CPColorPanelPreview _previewView; _CPColorPanelPreview _previewView;
@@ -80,8 +82,8 @@ CPColorPickerViewHeight = 370;
int _mode; 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. any picker in this list up to this point. In other words, call before creating a color panel.
*/ */
+ (void)provideColorPickerClass:(Class)aColorPickerSubclass + (void)provideColorPickerClass:(Class)aColorPickerSubclass
@@ -96,7 +98,7 @@ CPColorPickerViewHeight = 370;
{ {
if (!SharedColorPanel) if (!SharedColorPanel)
SharedColorPanel = [[CPColorPanel alloc] init]; SharedColorPanel = [[CPColorPanel alloc] init];
return SharedColorPanel; return SharedColorPanel;
} }
@@ -107,7 +109,7 @@ CPColorPickerViewHeight = 370;
+ (void)setPickerMode:(CPColorPanelMode)mode + (void)setPickerMode:(CPColorPanelMode)mode
{ {
var panel = [CPColorPanel sharedColorPanel]; var panel = [CPColorPanel sharedColorPanel];
[panel setMode: mode]; [panel setMode:mode];
} }
/* /*
@@ -116,7 +118,7 @@ CPColorPickerViewHeight = 370;
*/ */
- (id)init - (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)]; styleMask:(CPTitledWindowMask | CPClosableWindowMask | CPResizableWindowMask)];
if (self) if (self)
@@ -125,14 +127,14 @@ CPColorPickerViewHeight = 370;
[self setTitle:@"Color Panel"]; [self setTitle:@"Color Panel"];
[self setLevel:CPFloatingWindowLevel]; [self setLevel:CPFloatingWindowLevel];
[self setFloatingPanel:YES]; [self setFloatingPanel:YES];
[self setBecomesKeyOnlyIfNeeded:YES]; [self setBecomesKeyOnlyIfNeeded:YES];
[self setMinSize:CGSizeMake(219.0, 342.0)]; [self setMinSize:CGSizeMake(219.0, 342.0)];
[self setMaxSize:CGSizeMake(323.0, 537.0)]; [self setMaxSize:CGSizeMake(323.0, 537.0)];
} }
return self; return self;
} }
@@ -143,12 +145,12 @@ CPColorPickerViewHeight = 370;
{ {
_color = aColor; _color = aColor;
[_previewView setBackgroundColor: _color]; [_previewView setBackgroundColor: _color];
[CPApp sendAction:@selector(changeColor:) to:nil from:self]; [CPApp sendAction:@selector(changeColor:) to:nil from:self];
if (_target && _action) if (_target && _action)
[CPApp sendAction:_action to:_target from:self]; [CPApp sendAction:_action to:_target from:self];
[[CPNotificationCenter defaultCenter] [[CPNotificationCenter defaultCenter]
postNotificationName:CPColorPanelColorDidChangeNotification postNotificationName:CPColorPanelColorDidChangeNotification
object:self]; object:self];
@@ -165,7 +167,7 @@ CPColorPickerViewHeight = 370;
- (void)setColor:(CPColor)aColor updatePicker:(BOOL)bool - (void)setColor:(CPColor)aColor updatePicker:(BOOL)bool
{ {
[self setColor:aColor]; [self setColor:aColor];
if (bool) if (bool)
[_activePicker setColor:_color]; [_activePicker setColor:_color];
} }
@@ -232,30 +234,30 @@ CPColorPickerViewHeight = 370;
{ {
var picker = _colorPickers[[sender tag]], var picker = _colorPickers[[sender tag]],
view = [picker provideNewView:NO]; view = [picker provideNewView:NO];
if (!view) if (!view)
view = [picker provideNewView:YES]; view = [picker provideNewView:YES];
if (view == _currentView) if (view == _currentView)
return; return;
if (_currentView) if (_currentView)
[view setFrame:[_currentView frame]]; [view setFrame:[_currentView frame]];
else 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]; bounds = [[self contentView] bounds];
[view setFrameSize: CPSizeMake(bounds.size.width - 10, bounds.size.height - height)]; [view setFrameSize:CPSizeMake(bounds.size.width - 10, bounds.size.height - height)];
[view setFrameOrigin: CPPointMake(5, height)]; [view setFrameOrigin:CPPointMake(5, height)];
} }
[_currentView removeFromSuperview]; [_currentView removeFromSuperview];
[[self contentView] addSubview:view]; [[self contentView] addSubview:view];
_currentView = view; _currentView = view;
_activePicker = picker; _activePicker = picker;
[picker setColor:[self color]]; [picker setColor:[self color]];
} }
@@ -285,7 +287,7 @@ CPColorPickerViewHeight = 370;
_colorPickers = []; _colorPickers = [];
var count = [ColorPickerClasses count]; var count = [ColorPickerClasses count];
for (var i=0; i<count; i++) for (var i = 0; i < count; i++)
{ {
var currentPickerClass = ColorPickerClasses[i], var currentPickerClass = ColorPickerClasses[i],
currentPicker = [[currentPickerClass alloc] initWithPickerMask:0 colorPanel:self]; currentPicker = [[currentPickerClass alloc] initWithPickerMask:0 colorPanel:self];
@@ -297,29 +299,29 @@ CPColorPickerViewHeight = 370;
bounds = [contentView bounds]; bounds = [contentView bounds];
_toolbar = [[CPView alloc] initWithFrame:CGRectMake(0, 6, CGRectGetWidth(bounds), TOOLBAR_HEIGHT)]; _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, var totalToolbarWidth = count * ICON_WIDTH + (count - 1) * ICON_PADDING,
leftOffset = (CGRectGetWidth(bounds) - totalToolbarWidth) / 2.0, leftOffset = (CGRectGetWidth(bounds) - totalToolbarWidth) / 2.0,
buttonForLater = nil; buttonForLater = nil;
for (var i=0; i<count; i++) for (var i = 0; i < count; i++)
{ {
var image = [_colorPickers[i] provideNewButtonImage], var image = [_colorPickers[i] provideNewButtonImage],
highlightImage = [_colorPickers[i] provideNewAlternateButtonImage], 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 setTag:i];
[button setTarget:self]; [button setTarget:self];
[button setAction:@selector(_setPicker:)]; [button setAction:@selector(_setPicker:)];
[button setBordered:NO]; [button setBordered:NO];
[button setAutoresizingMask:CPViewMinXMargin|CPViewMaxXMargin]; [button setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin];
[button setImage:image]; [button setImage:image];
[button setAlternateImage:highlightImage]; [button setAlternateImage:highlightImage];
[_toolbar addSubview:button]; [_toolbar addSubview:button];
if (!buttonForLater) if (!buttonForLater)
buttonForLater = button; buttonForLater = button;
} }
@@ -330,7 +332,7 @@ CPColorPickerViewHeight = 370;
_previewView = [[_CPColorPanelPreview alloc] initWithFrame:CGRectInset([previewBox bounds], 2.0, 2.0)]; _previewView = [[_CPColorPanelPreview alloc] initWithFrame:CGRectInset([previewBox bounds], 2.0, 2.0)];
[_previewView setColorPanel:self]; [_previewView setColorPanel:self];
[_previewView setAutoresizingMask:CPViewWidthSizable]; [_previewView setAutoresizingMask:CPViewWidthSizable];
[previewBox setBackgroundColor:[CPColor colorWithWhite:0.8 alpha:1.0]]; [previewBox setBackgroundColor:[CPColor colorWithWhite:0.8 alpha:1.0]];
[previewBox setAutoresizingMask:CPViewWidthSizable]; [previewBox setAutoresizingMask:CPViewWidthSizable];
@@ -338,7 +340,7 @@ CPColorPickerViewHeight = 370;
[previewBox addSubview:_previewView]; [previewBox addSubview:_previewView];
var _previewLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + 10, 60, 15)]; var _previewLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + 10, 60, 15)];
[_previewLabel setStringValue: "Preview:"]; [_previewLabel setStringValue:"Preview:"];
[_previewLabel setTextColor:[CPColor blackColor]]; [_previewLabel setTextColor:[CPColor blackColor]];
[_previewLabel setAlignment:CPRightTextAlignment]; [_previewLabel setAlignment:CPRightTextAlignment];
@@ -350,8 +352,8 @@ CPColorPickerViewHeight = 370;
_swatchView = [[_CPColorPanelSwatches alloc] initWithFrame:CGRectInset([swatchBox bounds], 1.0, 1.0)]; _swatchView = [[_CPColorPanelSwatches alloc] initWithFrame:CGRectInset([swatchBox bounds], 1.0, 1.0)];
[_swatchView setColorPanel: self]; [_swatchView setColorPanel:self];
[_swatchView setAutoresizingMask: CPViewWidthSizable]; [_swatchView setAutoresizingMask:CPViewWidthSizable];
[swatchBox addSubview:_swatchView]; [swatchBox addSubview:_swatchView];
@@ -367,7 +369,7 @@ CPColorPickerViewHeight = 370;
[opacityLabel setAlignment:CPRightTextAlignment]; [opacityLabel setAlignment:CPRightTextAlignment];
_opacitySlider = [[CPSlider alloc] initWithFrame:CGRectMake(76, TOOLBAR_HEIGHT + PREVIEW_HEIGHT + 34, CGRectGetWidth(bounds) - 86, 20.0)]; _opacitySlider = [[CPSlider alloc] initWithFrame:CGRectMake(76, TOOLBAR_HEIGHT + PREVIEW_HEIGHT + 34, CGRectGetWidth(bounds) - 86, 20.0)];
[_opacitySlider setMinValue:0.0]; [_opacitySlider setMinValue:0.0];
[_opacitySlider setMaxValue:1.0]; [_opacitySlider setMaxValue:1.0];
@@ -415,37 +417,37 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
CPCookie _swatchCookie; CPCookie _swatchCookie;
} }
-(id)initWithFrame:(CPRect)aFrame - (id)initWithFrame:(CPRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
[self setBackgroundColor: [CPColor grayColor]]; [self setBackgroundColor: [CPColor grayColor]];
[self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]]; [self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]];
var whiteColor = [CPColor whiteColor]; var whiteColor = [CPColor whiteColor];
_swatchCookie = [[CPCookie alloc] initWithName: CPColorPanelSwatchesCookie]; _swatchCookie = [[CPCookie alloc] initWithName: CPColorPanelSwatchesCookie];
var colorList = [self startingColorList]; var colorList = [self startingColorList];
_swatches = []; _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 // 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)]; fillView = [[CPView alloc] initWithFrame:CGRectInset([view bounds], 1.0, 1.0)];
[view setBackgroundColor:whiteColor]; [view setBackgroundColor:whiteColor];
[fillView setBackgroundColor: (i < colorList.length) ? colorList[i] : whiteColor]; [fillView setBackgroundColor: (i < colorList.length) ? colorList[i] : whiteColor];
[view addSubview:fillView]; [view addSubview:fillView];
[self addSubview: view]; [self addSubview: view];
_swatches.push(view); _swatches.push(view);
} }
return self; return self;
} }
@@ -457,7 +459,8 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (CPArray)startingColorList - (CPArray)startingColorList
{ {
var cookieValue = [_swatchCookie value]; var cookieValue = [_swatchCookie value];
if(cookieValue == "")
if (cookieValue == "")
{ {
return [ return [
[CPColor blackColor], [CPColor blackColor],
@@ -471,11 +474,11 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
[CPColor yellowColor] [CPColor yellowColor]
]; ];
} }
var cookieValue = eval(cookieValue); var cookieValue = eval(cookieValue),
var result = []; result = [];
for(var i=0; i<cookieValue.length; i++) for (var i = 0; i < cookieValue.length; i++)
result.push([CPColor colorWithHexString: cookieValue[i]]); result.push([CPColor colorWithHexString: cookieValue[i]]);
return result; return result;
@@ -485,12 +488,12 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{ {
var result = []; var result = [];
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox // 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]); result.push([[[_swatches[i] subviews][0] backgroundColor] hexString]);
var future = new Date(); var future = new Date();
future.setYear(2019); future.setYear(2019);
[_swatchCookie setValue: JSON.stringify(result) expires:future domain: nil]; [_swatchCookie setValue: JSON.stringify(result) expires:future domain: nil];
} }
@@ -520,8 +523,8 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{ {
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil], var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
bounds = [self bounds]; 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; return NO;
[_colorPanel setColor: [self colorAtIndex:FLOOR(point.x / 13)] updatePicker: YES]; [_colorPanel setColor: [self colorAtIndex:FLOOR(point.x / 13)] updatePicker: YES];
@@ -535,21 +538,21 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
return NO; return NO;
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPArray arrayWithObject:CPColorDragType] owner:self]; [[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPArray arrayWithObject:CPColorDragType] owner:self];
var swatch = _swatches[FLOOR(point.x / 13)]; var swatch = _swatches[FLOOR(point.x / 13)];
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox // FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
_dragColor = [[swatch subviews][0] backgroundColor]; _dragColor = [[swatch subviews][0] backgroundColor];
var bounds = CPRectCreateCopy([swatch bounds]); var bounds = CPRectCreateCopy([swatch bounds]);
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox // 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)]; dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
[dragView setBackgroundColor:[CPColor blackColor]]; [dragView setBackgroundColor:[CPColor blackColor]];
[dragFillView setBackgroundColor:_dragColor]; [dragFillView setBackgroundColor:_dragColor];
[dragView addSubview:dragFillView]; [dragView addSubview:dragFillView];
[self dragView: dragView [self dragView: dragView
@@ -563,19 +566,19 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType - (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{ {
if(aType == CPColorDragType) if (aType == CPColorDragType)
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:_dragColor] forType:aType]; [aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:_dragColor] forType:aType];
} }
- (void)performDragOperation:(id <CPDraggingInfo>)aSender - (void)performDragOperation:(id <CPDraggingInfo>)aSender
{ {
var location = [self convertPoint:[aSender draggingLocation] fromView:nil], var location = [self convertPoint:[aSender draggingLocation] fromView:nil],
pasteboard = [aSender draggingPasteboard], pasteboard = [aSender draggingPasteboard],
swatch = nil; 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; return NO;
[self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex: FLOOR(location.x / 13)]; [self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex: FLOOR(location.x / 13)];
} }
@@ -590,9 +593,9 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (id)initWithFrame:(CPRect)aFrame - (id)initWithFrame:(CPRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
[self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]]; [self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]];
return self; return self;
} }
@@ -610,9 +613,9 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{ {
var pasteboard = [aSender draggingPasteboard]; var pasteboard = [aSender draggingPasteboard];
if(![pasteboard availableTypeFromArray:[CPColorDragType]]) if (![pasteboard availableTypeFromArray:[CPColorDragType]])
return NO; return NO;
var color = [CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]]; var color = [CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]];
[_colorPanel setColor:color updatePicker:YES]; [_colorPanel setColor:color updatePicker:YES];
} }
@@ -626,19 +629,19 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{ {
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil]; 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); var bounds = CPRectMake(0, 0, 15, 15);
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox // 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)]; dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
[dragView setBackgroundColor:[CPColor blackColor]]; [dragView setBackgroundColor:[CPColor blackColor]];
[dragFillView setBackgroundColor:[self backgroundColor]]; [dragFillView setBackgroundColor:[self backgroundColor]];
[dragView addSubview:dragFillView]; [dragView addSubview:dragFillView];
[self dragView: dragView [self dragView: dragView
at: CPPointMake(point.x - bounds.size.width / 2.0, point.y - bounds.size.height / 2.0) at: CPPointMake(point.x - bounds.size.width / 2.0, point.y - bounds.size.height / 2.0)
offset: CPPointMake(0.0, 0.0) offset: CPPointMake(0.0, 0.0)
@@ -650,7 +653,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType - (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{ {
if(aType == CPColorDragType) if (aType == CPColorDragType)
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:[self backgroundColor]] forType:aType]; [aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:[self backgroundColor]] forType:aType];
} }
+36 -39
View File
@@ -21,11 +21,11 @@
*/ */
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import "CPColorPanel.j"
#include "Platform/Platform.h" @import "CPView.j"
/*!
/*!
@ingroup appkit @ingroup appkit
@class CPColorPicker @class CPColorPicker
@@ -102,18 +102,18 @@
CPColor _cachedColor; CPColor _cachedColor;
} }
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel - (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
{ {
return [super initWithPickerMask:mask colorPanel: owningColorPanel]; return [super initWithPickerMask:mask colorPanel: owningColorPanel];
} }
-(id)initView - (id)initView
{ {
aFrame = CPRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight); aFrame = CPRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
_pickerView = [[CPView alloc] initWithFrame:aFrame]; _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)]; _brightnessSlider = [[CPSlider alloc] initWithFrame:CGRectMake(0, (aFrame.size.height - 34), aFrame.size.width, 15)];
@@ -136,17 +136,17 @@
[_pickerView addSubview:_brightnessSlider]; [_pickerView addSubview:_brightnessSlider];
} }
-(void)brightnessSliderDidChange:(id)sender - (void)brightnessSliderDidChange:(id)sender
{ {
[self updateColor]; [self updateColor];
} }
-(void)colorWheelDidChange:(id)sender - (void)colorWheelDidChange:(id)sender
{ {
[self updateColor]; [self updateColor];
} }
-(void)updateColor - (void)updateColor
{ {
var hue = [_hueSaturationView angle], var hue = [_hueSaturationView angle],
saturation = [_hueSaturationView distance], saturation = [_hueSaturationView distance],
@@ -223,7 +223,7 @@
float _radius; float _radius;
} }
-(id)initWithFrame:(CPRect)aFrame - (id)initWithFrame:(CPRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
@@ -261,19 +261,19 @@
return self; return self;
} }
-(void)setWheelBrightness:(float)brightness - (void)setWheelBrightness:(float)brightness
{ {
_blackWheelImage.style.opacity = 1.0 - 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]; [super setFrameSize:aSize];
[self setWheelSize:aSize]; [self setWheelSize:aSize];
} }
-(void)setWheelSize:(CPSize)aSize - (void)setWheelSize:(CPSize)aSize
{ {
var min = MIN(aSize.width, aSize.height); var min = MIN(aSize.width, aSize.height);
@@ -296,57 +296,55 @@
[self setAngle:[self degreesToRadians:_angle] distance:(_distance / 100.0) * _radius]; [self setAngle:[self degreesToRadians:_angle] distance:(_distance / 100.0) * _radius];
} }
-(void)setDelegate:(id)aDelegate - (void)setDelegate:(id)aDelegate
{ {
_delegate = aDelegate; _delegate = aDelegate;
} }
-(id)delegate - (id)delegate
{ {
return _delegate; return _delegate;
} }
-(float)angle - (float)angle
{ {
return _angle; return _angle;
} }
-(float)distance - (float)distance
{ {
return _distance; return _distance;
} }
-(void)mouseDown:(CPEvent)anEvent - (void)mouseDown:(CPEvent)anEvent
{ {
[self reposition:anEvent]; [self reposition:anEvent];
} }
-(void)mouseDragged:(CPEvent)anEvent - (void)mouseDragged:(CPEvent)anEvent
{ {
[self reposition:anEvent]; [self reposition:anEvent];
} }
-(void)reposition:(CPEvent)anEvent - (void)reposition:(CPEvent)anEvent
{ {
var bounds = [self bounds], var bounds = [self bounds],
location = [self convertPoint:[anEvent locationInWindow] fromView:nil]; location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
midX = CGRectGetMidX(bounds),
var midX = CGRectGetMidX(bounds); midY = CGRectGetMidY(bounds),
var 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);
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);
[self setAngle:angle distance:distance]; [self setAngle:angle distance:distance];
[_delegate colorWheelDidChange:self]; [_delegate colorWheelDidChange:self];
} }
-(void)setAngle:(int)angle distance:(float)distance - (void)setAngle:(int)angle distance:(float)distance
{ {
var bounds = [self bounds]; var bounds = [self bounds],
var midX = CGRectGetMidX(bounds); midX = CGRectGetMidX(bounds),
var midY = CGRectGetMidY(bounds); midY = CGRectGetMidY(bounds);
_angle = [self radiansToDegrees:angle]; _angle = [self radiansToDegrees:angle];
_distance = (distance / _radius) * 100.0; _distance = (distance / _radius) * 100.0;
@@ -354,23 +352,22 @@
[_crosshair setFrameOrigin:CPPointMake(COS(angle) * distance + midX - 2.0, SIN(angle) * distance + midY - 2.0)]; [_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], var hsb = [aColor hsbComponents],
bounds = [self bounds]; bounds = [self bounds],
angle = [self degreesToRadians:hsb[0]],
var angle = [self degreesToRadians:hsb[0]],
distance = (hsb[1] / 100.0) * _radius; distance = (hsb[1] / 100.0) * _radius;
[self setAngle:angle distance:distance]; [self setAngle:angle distance:distance];
} }
-(int)radiansToDegrees:(float)radians - (int)radiansToDegrees:(float)radians
{ {
return ((-radians / PI) * 180 + 360) % 360; return ((-radians / PI) * 180 + 360) % 360;
} }
-(float)degreesToRadians:(float)degrees - (float)degreesToRadians:(float)degrees
{ {
return -(((degrees - 360) / 180) * PI); return -(((degrees - 360) / 180) * PI);
} }
+36 -30
View File
@@ -29,7 +29,7 @@
var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiveNotification"; var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiveNotification";
/*! /*!
@ingroup appkit @ingroup appkit
@class CPColorWell @class CPColorWell
@@ -41,7 +41,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{ {
BOOL _active; BOOL _active;
BOOL _bordered; BOOL _bordered;
CPColor _color; CPColor _color;
CPView _wellView; CPView _wellView;
} }
@@ -49,19 +49,19 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
_active = NO; _active = NO;
_bordered = YES; _bordered = YES;
_color = [CPColor whiteColor]; _color = [CPColor whiteColor];
[self drawBezelWithHighlight:NO]; [self drawBezelWithHighlight:NO];
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)]; [self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
[self _registerForNotifications]; [self _registerForNotifications];
} }
return self; return self;
} }
@@ -97,9 +97,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{ {
if (_bordered == bordered) if (_bordered == bordered)
return; return;
_bordered = bordered; _bordered = bordered;
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)]; [self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
} }
@@ -120,9 +120,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{ {
if (_color == aColor) if (_color == aColor)
return; return;
_color = aColor; _color = aColor;
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)]; [self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
} }
@@ -137,7 +137,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
// Activating and Deactivating Color Wells // 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. If exclusive is \c YES, deactivates any other CPColorWells. \c NO, keeps them active.
@param shouldBeExclusive whether other color wells should be deactivated. @param shouldBeExclusive whether other color wells should be deactivated.
*/ */
@@ -152,9 +152,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
if ([self isActive]) if ([self isActive])
return; return;
_active = YES; _active = YES;
[[CPNotificationCenter defaultCenter] [[CPNotificationCenter defaultCenter]
addObserver:self addObserver:self
selector:@selector(colorPanelDidChangeColor:) selector:@selector(colorPanelDidChangeColor:)
@@ -169,9 +169,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{ {
if (![self isActive]) if (![self isActive])
return; return;
_active = NO; _active = NO;
[[CPNotificationCenter defaultCenter] [[CPNotificationCenter defaultCenter]
removeObserver:self removeObserver:self
name:CPColorPanelColorDidChangeNotification name:CPColorPanelColorDidChangeNotification
@@ -202,19 +202,19 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{ {
_wellView = [[CPView alloc] initWithFrame:aRect]; _wellView = [[CPView alloc] initWithFrame:aRect];
[_wellView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; [_wellView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[self addSubview:_wellView]; [self addSubview:_wellView];
} }
else else
[_wellView setFrame:aRect]; [_wellView setFrame:aRect];
[_wellView setBackgroundColor:_color]; [_wellView setBackgroundColor:_color];
} }
- (void)colorPanelDidChangeColor:(CPNotification)aNotification - (void)colorPanelDidChangeColor:(CPNotification)aNotification
{ {
[self takeColorFrom:[aNotification object]]; [self takeColorFrom:[aNotification object]];
[self sendAction:[self action] to:[self target]]; [self sendAction:[self action] to:[self target]];
} }
@@ -231,25 +231,31 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
- (void)mouseDown:(CPEvent)anEvent - (void)mouseDown:(CPEvent)anEvent
{ {
if (![self isEnabled])
return;
[self drawBezelWithHighlight:YES]; [self drawBezelWithHighlight:YES];
} }
- (void)mouseDragged:(CPEvent)anEvent - (void)mouseDragged:(CPEvent)anEvent
{ {
if (![self isEnabled])
return;
[self drawBezelWithHighlight:CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil])]; [self drawBezelWithHighlight:CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil])];
} }
-(void)mouseUp:(CPEvent)anEvent - (void)mouseUp:(CPEvent)anEvent
{ {
[self drawBezelWithHighlight:NO]; [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; return;
[self activate:YES]; [self activate:YES];
var colorPanel = [CPColorPanel sharedColorPanel]; var colorPanel = [CPColorPanel sharedColorPanel];
[colorPanel setColor:_color]; [colorPanel setColor:_color];
[colorPanel orderFront:self]; [colorPanel orderFront:self];
} }
@@ -268,11 +274,11 @@ var CPColorWellColorKey = "CPColorWellColorKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super initWithCoder:aCoder]; self = [super initWithCoder:aCoder];
if (self) if (self)
{ {
_active = NO; _active = NO;
_bordered = [aCoder decodeObjectForKey:CPColorWellBorderedKey]; _bordered = [aCoder decodeBoolForKey:CPColorWellBorderedKey];
_color = [aCoder decodeObjectForKey:CPColorWellColorKey]; _color = [aCoder decodeObjectForKey:CPColorWellColorKey];
[self drawBezelWithHighlight:NO]; [self drawBezelWithHighlight:NO];
@@ -280,7 +286,7 @@ var CPColorWellColorKey = "CPColorWellColorKey",
[self _registerForNotifications]; [self _registerForNotifications];
} }
return self; return self;
} }
@@ -290,17 +296,17 @@ var CPColorWellColorKey = "CPColorWellColorKey",
*/ */
- (void)encodeWithCoder:(CPCoder)aCoder - (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. // should just automatically be created programmatically as needed.
var actualSubviews = _subviews; var actualSubviews = _subviews;
_subviews = [_subviews copy]; _subviews = [_subviews copy];
[_subviews removeObjectIdenticalTo:_wellView]; [_subviews removeObjectIdenticalTo:_wellView];
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
_subviews = actualSubviews; _subviews = actualSubviews;
[aCoder encodeObject:_color forKey:CPColorWellColorKey]; [aCoder encodeObject:_color forKey:CPColorWellColorKey];
[aCoder encodeObject:_bordered forKey:CPColorWellBorderedKey]; [aCoder encodeObject:_bordered forKey:CPColorWellBorderedKey];
} }
+16 -15
View File
@@ -23,6 +23,7 @@
@import "CPEvent.j" @import "CPEvent.j"
@import "CPPlatform.j" @import "CPPlatform.j"
// Browser Engines // Browser Engines
CPUnknownBrowserEngine = 0; CPUnknownBrowserEngine = 0;
CPGeckoBrowserEngine = 1; CPGeckoBrowserEngine = 1;
@@ -77,23 +78,23 @@ if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
USER_AGENT = window.navigator.userAgent; USER_AGENT = window.navigator.userAgent;
// Opera // Opera
if (window.opera) if (typeof window !== "undefined" && window.opera)
{ {
PLATFORM_ENGINE = CPOperaBrowserEngine; PLATFORM_ENGINE = CPOperaBrowserEngine;
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature; PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
} }
// Internet Explorer // Internet Explorer
else if (window.attachEvent) // Must follow Opera check. else if (typeof window !== "undefined" && window.attachEvent) // Must follow Opera check.
{ {
PLATFORM_ENGINE = CPInternetExplorerBrowserEngine; PLATFORM_ENGINE = CPInternetExplorerBrowserEngine;
// Features we can only be sure of with IE (no known independent tests) // Features we can only be sure of with IE (no known independent tests)
PLATFORM_FEATURES |= CPVMLFeature; PLATFORM_FEATURES |= CPVMLFeature;
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport; PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
PLATFORM_FEATURES |= CPJavaScriptShadowFeature; PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
PLATFORM_FEATURES |= CPOpacityRequiresFilterFeature; PLATFORM_FEATURES |= CPOpacityRequiresFilterFeature;
PLATFORM_FEATURES &= ~CPInputTypeCanBeChangedFeature; PLATFORM_FEATURES &= ~CPInputTypeCanBeChangedFeature;
@@ -103,7 +104,7 @@ else if (window.attachEvent) // Must follow Opera check.
else if (USER_AGENT.indexOf("AppleWebKit/") != -1) else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
{ {
PLATFORM_ENGINE = CPWebKitBrowserEngine; PLATFORM_ENGINE = CPWebKitBrowserEngine;
// Features we can only be sure of with WebKit (no known independent tests) // Features we can only be sure of with WebKit (no known independent tests)
PLATFORM_FEATURES |= CPCSSRGBAFeature; PLATFORM_FEATURES |= CPCSSRGBAFeature;
PLATFORM_FEATURES |= CPHTMLContentEditableFeature; PLATFORM_FEATURES |= CPHTMLContentEditableFeature;
@@ -114,7 +115,7 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
PLATFORM_FEATURES |= CPJavascriptClipboardEventsFeature; PLATFORM_FEATURES |= CPJavascriptClipboardEventsFeature;
PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature; PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature;
PLATFORM_FEATURES |= CPJavaScriptShadowFeature; PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length, var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length,
versionEnd = USER_AGENT.indexOf(" ", versionStart), versionEnd = USER_AGENT.indexOf(" ", versionStart),
versionString = USER_AGENT.substring(versionStart, versionEnd), versionString = USER_AGENT.substring(versionStart, versionEnd),
@@ -122,7 +123,7 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
majorVersion = parseInt(versionString.substring(0, versionDivision)), majorVersion = parseInt(versionString.substring(0, versionDivision)),
minorVersion = parseInt(versionString.substr(versionDivision + 1)); 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; PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
// FIXME this is a terrible hack to get around this bug: // FIXME this is a terrible hack to get around this bug:
@@ -144,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. else if (USER_AGENT.indexOf("Gecko") !== -1) // Must follow KHTML check.
{ {
PLATFORM_ENGINE = CPGeckoBrowserEngine; PLATFORM_ENGINE = CPGeckoBrowserEngine;
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature; PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
var index = USER_AGENT.indexOf("Firefox"), var index = USER_AGENT.indexOf("Firefox"),
version = (index === -1) ? 2.0 : parseFloat(USER_AGENT.substring(index + "Firefox".length + 1)); version = (index === -1) ? 2.0 : parseFloat(USER_AGENT.substring(index + "Firefox".length + 1));
if (version >= 3.0) if (version >= 3.0)
PLATFORM_FEATURES |= CPCSSRGBAFeature; PLATFORM_FEATURES |= CPCSSRGBAFeature;
@@ -165,16 +166,16 @@ if (typeof document != "undefined")
if (canvasElement && canvasElement.getContext) if (canvasElement && canvasElement.getContext)
{ {
PLATFORM_FEATURES |= CPHTMLCanvasFeature; PLATFORM_FEATURES |= CPHTMLCanvasFeature;
// Detect Canvas setTransform/transform support // Detect Canvas setTransform/transform support
var context = document.createElement("canvas").getContext("2d"); var context = document.createElement("canvas").getContext("2d");
if (context && context.setTransform && context.transform) if (context && context.setTransform && context.transform)
PLATFORM_FEATURES |= CPJavaScriptCanvasTransformFeature; PLATFORM_FEATURES |= CPJavaScriptCanvasTransformFeature;
} }
var DOMElement = document.createElement("div"); var DOMElement = document.createElement("div");
// Detect whether we have innerText or textContent (or neither) // Detect whether we have innerText or textContent (or neither)
if (DOMElement.innerText != undefined) if (DOMElement.innerText != undefined)
PLATFORM_FEATURES |= CPJavascriptInnerTextFeature; PLATFORM_FEATURES |= CPJavascriptInnerTextFeature;
+176 -64
View File
@@ -23,9 +23,8 @@
@import "CPFont.j" @import "CPFont.j"
@import "CPShadow.j" @import "CPShadow.j"
@import "CPView.j" @import "CPView.j"
@import "CPKeyValueBinding.j"
#include "CoreGraphics/CGGeometry.h"
#include "Platform/Platform.h"
CPLeftTextAlignment = 0; CPLeftTextAlignment = 0;
CPRightTextAlignment = 1; CPRightTextAlignment = 1;
@@ -75,7 +74,7 @@ CPControlTextDidEndEditingNotification = "CPControlTextDidEndEditingNotific
var CPControlBlackColor = [CPColor blackColor]; var CPControlBlackColor = [CPColor blackColor];
/*! /*!
@ingroup appkit @ingroup appkit
@class CPControl @class CPControl
@@ -84,7 +83,7 @@ var CPControlBlackColor = [CPColor blackColor];
@implementation CPControl : CPView @implementation CPControl : CPView
{ {
id _value; id _value;
// Target-Action Support // Target-Action Support
id _target; id _target;
SEL _action; SEL _action;
@@ -126,16 +125,46 @@ var CPControlBlackColor = [CPColor blackColor];
@"max-size"]]; @"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 - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
_sendActionOn = CPLeftMouseUpMask; _sendActionOn = CPLeftMouseUpMask;
_trackingMouseDownFlags = 0; _trackingMouseDownFlags = 0;
} }
return self; return self;
} }
@@ -180,15 +209,16 @@ var CPControlBlackColor = [CPColor blackColor];
*/ */
- (void)sendAction:(SEL)anAction to:(id)anObject - (void)sendAction:(SEL)anAction to:(id)anObject
{ {
[self _reverseSetBinding];
[CPApp sendAction:anAction to:anObject from:self]; [CPApp sendAction:anAction to:anObject from:self];
} }
- (int)sendActionOn:(int)mask - (int)sendActionOn:(int)mask
{ {
var previousMask = _sendActionOn; var previousMask = _sendActionOn;
_sendActionOn = mask; _sendActionOn = mask;
return previousMask; return previousMask;
} }
@@ -201,7 +231,7 @@ var CPControlBlackColor = [CPColor blackColor];
{ {
if (_toolTip == aToolTip) if (_toolTip == aToolTip)
return; return;
_toolTip = aToolTip; _toolTip = aToolTip;
#if PLATFORM(DOM) #if PLATFORM(DOM)
@@ -236,7 +266,7 @@ var CPControlBlackColor = [CPColor blackColor];
// Some subclasses should redefine this with CPLeftMouseDraggedMask // Some subclasses should redefine this with CPLeftMouseDraggedMask
if (flag) if (flag)
_sendActionOn |= CPPeriodicMask; _sendActionOn |= CPPeriodicMask;
else else
_sendActionOn &= ~CPPeriodicMask; _sendActionOn &= ~CPPeriodicMask;
} }
@@ -248,16 +278,15 @@ var CPControlBlackColor = [CPColor blackColor];
- (void)trackMouse:(CPEvent)anEvent - (void)trackMouse:(CPEvent)anEvent
{ {
var type = [anEvent type], 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); isWithinFrame = [self tracksMouseOutsideOfFrame] || CGRectContainsPoint([self bounds], currentLocation);
if (type === CPLeftMouseUp) if (type === CPLeftMouseUp)
{ {
[self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:YES]; [self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:YES];
_trackingMouseDownFlags = 0; _trackingMouseDownFlags = 0;
} }
else else
{ {
if (type === CPLeftMouseDown) if (type === CPLeftMouseDown)
@@ -271,20 +300,20 @@ var CPControlBlackColor = [CPColor blackColor];
{ {
if (!_trackingWasWithinFrame) if (!_trackingWasWithinFrame)
_continuousTracking = [self startTrackingAt:currentLocation]; _continuousTracking = [self startTrackingAt:currentLocation];
else if (_continuousTracking) else if (_continuousTracking)
_continuousTracking = [self continueTracking:_previousTrackingLocation at:currentLocation]; _continuousTracking = [self continueTracking:_previousTrackingLocation at:currentLocation];
} }
else else
[self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:NO]; [self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:NO];
} }
[CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES]; [CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
} }
if ((_sendActionOn & (1 << type)) && isWithinFrame) if ((_sendActionOn & (1 << type)) && isWithinFrame)
[self sendAction:_action to:_target]; [self sendAction:_action to:_target];
_trackingWasWithinFrame = isWithinFrame; _trackingWasWithinFrame = isWithinFrame;
_previousTrackingLocation = currentLocation; _previousTrackingLocation = currentLocation;
} }
@@ -298,13 +327,26 @@ var CPControlBlackColor = [CPColor blackColor];
return 0; return 0;
} }
- (void)performClick:(id)sender - (void)performClick:(id)sender
{ {
if (![self isEnabled])
return;
[self highlight:YES]; [self highlight:YES];
[self setState:[self nextState]]; [self setState:[self nextState]];
[self sendAction:[self action] to:[self target]];
try
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO]; {
[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 - (void)unhighlightButtonTimerDidFinish:(id)sender
@@ -320,7 +362,7 @@ var CPControlBlackColor = [CPColor blackColor];
- (BOOL)startTrackingAt:(CGPoint)aPoint - (BOOL)startTrackingAt:(CGPoint)aPoint
{ {
[self highlight:YES]; [self highlight:YES];
return (_sendActionOn & CPPeriodicMask) || (_sendActionOn & CPLeftMouseDraggedMask); return (_sendActionOn & CPPeriodicMask) || (_sendActionOn & CPLeftMouseDraggedMask);
} }
@@ -338,7 +380,7 @@ var CPControlBlackColor = [CPColor blackColor];
{ {
if (![self isEnabled]) if (![self isEnabled])
return; return;
[self trackMouse:anEvent]; [self trackMouse:anEvent];
} }
@@ -356,7 +398,7 @@ var CPControlBlackColor = [CPColor blackColor];
- (void)setObjectValue:(id)anObject - (void)setObjectValue:(id)anObject
{ {
_value = anObject; _value = anObject;
[self setNeedsLayout]; [self setNeedsLayout];
[self setNeedsDisplay:YES]; [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 - (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 - (void)setStringValue:(CPString)anObject
{ {
@@ -485,54 +527,124 @@ var CPControlBlackColor = [CPColor blackColor];
[self setStringValue:[sender stringValue]]; [self setStringValue:[sender stringValue]];
} }
- (void)textDidBeginEditing:(CPNotification)note - (void)textDidBeginEditing:(CPNotification)note
{ {
//this looks to prevent false propagation of notifications for other objects //this looks to prevent false propagation of notifications for other objects
if([note object] != self) if ([note object] != self)
return; return;
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidBeginEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]]; [[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 //this looks to prevent false propagation of notifications for other objects
if([note object] != self) if ([note object] != self)
return; return;
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidChangeNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]]; [[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 //this looks to prevent false propagation of notifications for other objects
if([note object] != self) if ([note object] != self)
return; return;
[self _reverseSetBinding];
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]]; [[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
} }
#define BRIDGE(UPPERCASE, LOWERCASE, ATTRIBUTENAME) \ - (void)setAlignment:(CPTextAlignment)alignment
/*! Sets the value for ATTRIBUTENAME */\ {
- (void)set##UPPERCASE:(id)aValue\ [self setValue:alignment forThemeAttribute:@"alignment"];
{\
[self setValue:aValue forThemeAttribute:ATTRIBUTENAME];\
}\
/*! Returns the current value for ATTRIBUTENAME */\
- (id)LOWERCASE\
{\
return [self valueForThemeAttribute:ATTRIBUTENAME];\
} }
BRIDGE(Alignment, alignment, "alignment") - (CPTextAlignment)alignment
BRIDGE(VerticalAlignment, verticalAlignment, "vertical-alignment") {
BRIDGE(LineBreakMode, lineBreakMode, "line-break-mode") return [self valueForThemeAttribute:@"alignment"];
BRIDGE(TextColor, textColor, "text-color") }
BRIDGE(Font, font, "font")
BRIDGE(TextShadowColor, textShadowColor, "text-shadow-color") - (void)setVerticalAlignment:(CPTextVerticalAlignment)alignment
BRIDGE(TextShadowOffset, textShadowOffset, "text-shadow-offset") {
BRIDGE(ImagePosition, imagePosition, "image-position") [self setValue:alignment forThemeAttribute:@"vertical-alignment"];
BRIDGE(ImageScaling, imageScaling, "image-scaling") }
- (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 - (void)setEnabled:(BOOL)isEnabled
{ {
@@ -570,7 +682,7 @@ BRIDGE(ImageScaling, imageScaling, "image-scaling")
var CPControlValueKey = "CPControlValueKey", var CPControlValueKey = "CPControlValueKey",
CPControlControlStateKey = @"CPControlControlStateKey", CPControlControlStateKey = @"CPControlControlStateKey",
CPControlIsEnabledKey = "CPControlIsEnabledKey", CPControlIsEnabledKey = "CPControlIsEnabledKey",
CPControlTargetKey = "CPControlTargetKey", CPControlTargetKey = "CPControlTargetKey",
CPControlActionKey = "CPControlActionKey", CPControlActionKey = "CPControlActionKey",
CPControlSendActionOnKey = "CPControlSendActionOnKey", CPControlSendActionOnKey = "CPControlSendActionOnKey",
@@ -600,7 +712,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
[self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]]; [self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]];
[self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]]; [self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]];
} }
return self; return self;
} }
@@ -636,7 +748,7 @@ var _CPControlSizeIdentifiers = [],
_CPControlSizeIdentifiers[CPRegularControlSize] = "Regular"; _CPControlSizeIdentifiers[CPRegularControlSize] = "Regular";
_CPControlSizeIdentifiers[CPSmallControlSize] = "Small"; _CPControlSizeIdentifiers[CPSmallControlSize] = "Small";
_CPControlSizeIdentifiers[CPMiniControlSize] = "Mini"; _CPControlSizeIdentifiers[CPMiniControlSize] = "Mini";
function _CPControlIdentifierForControlSize(aControlSize) function _CPControlIdentifierForControlSize(aControlSize)
{ {
return _CPControlSizeIdentifiers[aControlSize]; return _CPControlSizeIdentifiers[aControlSize];
@@ -647,21 +759,21 @@ function _CPControlColorWithPatternImage(sizes, aClassName)
var index = 1, var index = 1,
count = arguments.length, count = arguments.length,
identifier = ""; identifier = "";
for (; index < count; ++index) for (; index < count; ++index)
identifier += arguments[index]; identifier += arguments[index];
var color = _CPControlCachedColorWithPatternImages[identifier]; var color = _CPControlCachedColorWithPatternImages[identifier];
if (!color) if (!color)
{ {
var bundle = [CPBundle bundleForClass:[CPControl class]]; var bundle = [CPBundle bundleForClass:[CPControl class]];
color = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:aClassName + "/" + identifier + ".png"] size:sizes[identifier]]]; color = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:aClassName + "/" + identifier + ".png"] size:sizes[identifier]]];
_CPControlCachedColorWithPatternImages[identifier] = color; _CPControlCachedColorWithPatternImages[identifier] = color;
} }
return color; return color;
} }
@@ -670,17 +782,17 @@ function _CPControlThreePartImagePattern(isVertical, sizes, aClassName)
var index = 2, var index = 2,
count = arguments.length, count = arguments.length,
identifier = ""; identifier = "";
for (; index < count; ++index) for (; index < count; ++index)
identifier += arguments[index]; identifier += arguments[index];
var color = _CPControlCachedThreePartImagePattern[identifier]; var color = _CPControlCachedThreePartImagePattern[identifier];
if (!color) if (!color)
{ {
var bundle = [CPBundle bundleForClass:[CPControl class]], var bundle = [CPBundle bundleForClass:[CPControl class]],
path = aClassName + "/" + identifier; path = aClassName + "/" + identifier;
sizes = sizes[identifier]; sizes = sizes[identifier];
color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:[ 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 + "1.png"] size:sizes[1]],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "2.png"] size:sizes[2]] [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "2.png"] size:sizes[2]]
] isVertical:isVertical]]; ] isVertical:isVertical]];
_CPControlCachedThreePartImagePattern[identifier] = color; _CPControlCachedThreePartImagePattern[identifier] = color;
} }
return 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> @import <Foundation/CPString.j>
/*! /*!
@ingroup appkit @ingroup appkit
@class CPCookie @class CPCookie
CPCookie is the Cappuccino interface to a web browser cookie. You can set the name CPCookie is the Cappuccino interface to a web browser cookie. You can set the name
@@ -33,7 +33,7 @@
{ {
CPString _cookieName; CPString _cookieName;
CPString _cookieValue; CPString _cookieValue;
CPString _expires; CPString _expires;
} }
@@ -44,7 +44,7 @@
- (id)initWithName:(CPString)aName - (id)initWithName:(CPString)aName
{ {
self = [super init]; self = [super init];
_cookieName = aName; _cookieName = aName;
_cookieValue = [self _readCookieValue]; _cookieValue = [self _readCookieValue];
@@ -83,30 +83,39 @@
*/ */
- (void)setValue:(CPString)value expires:(CPDate)date domain:(CPString)domain - (void)setValue:(CPString)value expires:(CPDate)date domain:(CPString)domain
{ {
if(date) if (date)
var expires = "; expires="+date.toGMTString(); var expires = "; expires=" + date.toGMTString();
else else
var expires = ""; var expires = "";
if(domain) if (domain)
domain = "; domain="+domain; domain = "; domain=" + domain;
else else
domain = ""; 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 */ /* @ignore */
- (CPString)_readCookieValue - (CPString)_readCookieValue
{ {
var nameEQ = _cookieName + "="; #if PLATFORM(DOM)
var ca = document.cookie.split(';'); var nameEQ = _cookieName + "=",
for(var i=0;i < ca.length;i++) { ca = document.cookie.split(';');
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length); for (var i = 0; i < ca.length; i++)
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); {
} var c = ca[i];
return ""; 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 @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 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, var currentCursor = nil,
cursorStack = [], cursorStack = [],
@@ -61,9 +61,9 @@ var currentCursor = nil,
if (CPBrowserIsEngine(CPGeckoBrowserEngine)) if (CPBrowserIsEngine(CPGeckoBrowserEngine))
cursorURLFormat += ", default"; cursorURLFormat += ", default";
} }
var url = [CPString stringWithFormat:cursorURLFormat, imageName]; var url = [CPString stringWithFormat:cursorURLFormat, imageName];
return [[CPCursor alloc] initWithCSSString:url]; return [[CPCursor alloc] initWithCSSString:url];
} }
@@ -96,7 +96,7 @@ var currentCursor = nil,
{ {
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine)) if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
return [CPCursor cursorWithCSSString:"s-resize"]; // WebKit | FF | opera return [CPCursor cursorWithCSSString:"s-resize"]; // WebKit | FF | opera
} }
@@ -167,18 +167,22 @@ var currentCursor = nil,
{ {
if (CPBrowserIsEngine(CPWebKitBrowserEngine)) if (CPBrowserIsEngine(CPWebKitBrowserEngine))
return [CPCursor cursorWithCSSString:@"-webkit-grab"]; 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 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 + (CPCursor)closedHandCursor
{ {
if (CPBrowserIsEngine(CPWebKitBrowserEngine)) if (CPBrowserIsEngine(CPWebKitBrowserEngine))
return [CPCursor cursorWithCSSString:@"-webkit-grabbing"]; 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 + (CPCursor)disappearingItemCursor
@@ -193,7 +197,7 @@ var currentCursor = nil,
+ (void)unhide + (void)unhide
{ {
[self _setCursorCSS:[currentCursor _cssString]] [self _setCursorCSS:[currentCursor _cssString]];
} }
+ (void)setHiddenUntilMouseMoves:(BOOL)flag + (void)setHiddenUntilMouseMoves:(BOOL)flag
@@ -206,9 +210,10 @@ var currentCursor = nil,
- (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot - (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot
{ {
return [self initWithCSSString:"url(" + [image filename] + ")"]; return [self initWithCSSString:"url(" + [image filename] + "), auto"];
} }
- (void)mouseEntered:(CPEvent)event - (void)mouseEntered:(CPEvent)event
{ {
} }
@@ -219,7 +224,7 @@ var currentCursor = nil,
- (void)set - (void)set
{ {
currentCursor = self; currentCursor = self;
#if PLATFORM(DOM) #if PLATFORM(DOM)
[[self class] _setCursorCSS:_cssString]; [[self class] _setCursorCSS:_cssString];
+51 -50
View File
@@ -23,6 +23,7 @@
@import <Foundation/CPString.j> @import <Foundation/CPString.j>
@import <Foundation/CPArray.j> @import <Foundation/CPArray.j>
@import "CPApplication.j"
@import "CPResponder.j" @import "CPResponder.j"
@import "CPSavePanel.j" @import "CPSavePanel.j"
@import "CPViewController.j" @import "CPViewController.j"
@@ -82,7 +83,7 @@ CPDocumentDidFailToSaveNotification = @"CPDocumentDidFailToSaveNotification";
var CPDocumentUntitledCount = 0; var CPDocumentUntitledCount = 0;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPDocument @class CPDocument
@@ -120,7 +121,7 @@ var CPDocumentUntitledCount = 0;
- (id)init - (id)init
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_windowControllers = []; _windowControllers = [];
@@ -131,7 +132,7 @@ var CPDocumentUntitledCount = 0;
[self setNextResponder:CPApp]; [self setNextResponder:CPApp];
} }
return self; return self;
} }
@@ -144,10 +145,10 @@ var CPDocumentUntitledCount = 0;
- (id)initWithType:(CPString)aType error:({CPError})anError - (id)initWithType:(CPString)aType error:({CPError})anError
{ {
self = [self init]; self = [self init];
if (self) if (self)
[self setFileType:aType]; [self setFileType:aType];
return self; 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 - (id)initWithContentsOfURL:(CPURL)anAbsoluteURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
{ {
self = [self init]; self = [self init];
if (self) if (self)
{ {
[self setFileURL:anAbsoluteURL]; [self setFileURL:anAbsoluteURL];
@@ -173,7 +174,7 @@ var CPDocumentUntitledCount = 0;
[self readFromURL:anAbsoluteURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo]; [self readFromURL:anAbsoluteURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
} }
return self; 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 - (id)initForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
{ {
self = [self init]; self = [self init];
if (self) if (self)
{ {
[self setFileURL:anAbsoluteURL]; [self setFileURL:anAbsoluteURL];
@@ -198,7 +199,7 @@ var CPDocumentUntitledCount = 0;
[self readFromURL:absoluteContentsURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo]; [self readFromURL:absoluteContentsURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
} }
return self; return self;
} }
@@ -281,7 +282,7 @@ var CPDocumentUntitledCount = 0;
{ {
var view = [viewController view], var view = [viewController view],
viewFrame = [view frame]; viewFrame = [view frame];
viewFrame.origin = CGPointMake(50, 50); viewFrame.origin = CGPointMake(50, 50);
var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask]; var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
@@ -381,14 +382,14 @@ var CPDocumentUntitledCount = 0;
{ {
if (_fileURL) if (_fileURL)
return [_fileURL lastPathComponent]; return [_fileURL lastPathComponent];
if (!_untitledDocumentIndex) if (!_untitledDocumentIndex)
_untitledDocumentIndex = ++CPDocumentUntitledCount; _untitledDocumentIndex = ++CPDocumentUntitledCount;
if (_untitledDocumentIndex == 1)
return @"Untitled";
return @"Untitled " + _untitledDocumentIndex; if (_untitledDocumentIndex == 1)
return @"Untitled";
return @"Untitled " + _untitledDocumentIndex;
} }
- (CPString)viewCibName - (CPString)viewCibName
@@ -457,7 +458,7 @@ var CPDocumentUntitledCount = 0;
return; return;
_fileURL = aFileURL; _fileURL = aFileURL;
[_windowControllers makeObjectsPerformSelector:@selector(synchronizeWindowTitleWithDocumentName)]; [_windowControllers makeObjectsPerformSelector:@selector(synchronizeWindowTitleWithDocumentName)];
} }
@@ -509,21 +510,21 @@ var CPDocumentUntitledCount = 0;
// If we got this far and it wasn't an HTTP request, then everything is fine. // If we got this far and it wasn't an HTTP request, then everything is fine.
if (![aResponse isKindOfClass:[CPHTTPURLResponse class]]) if (![aResponse isKindOfClass:[CPHTTPURLResponse class]])
return; return;
var statusCode = [aResponse statusCode]; var statusCode = [aResponse statusCode];
// Nothing to do if everything is hunky dory. // Nothing to do if everything is hunky dory.
if (statusCode === 200) if (statusCode === 200)
return; return;
var session = aConnection.session; var session = aConnection.session;
if (aConnection == _readConnection) if (aConnection == _readConnection)
{ {
[aConnection cancel]; [aConnection cancel];
alert("There was an error retrieving the document."); alert("There was an error retrieving the document.");
objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo); objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
} }
else else
@@ -532,23 +533,23 @@ var CPDocumentUntitledCount = 0;
if (statusCode == 409) if (statusCode == 409)
{ {
[aConnection cancel]; [aConnection cancel];
if (confirm("There already exists a file with that name, would you like to overwrite it?")) if (confirm("There already exists a file with that name, would you like to overwrite it?"))
{ {
[_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"]; [_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"];
[aConnection start]; [aConnection start];
} }
else else
{ {
if (session.saveOperation != CPSaveToOperation) if (session.saveOperation != CPSaveToOperation)
{ {
_changeCount += session.changeCount; _changeCount += session.changeCount;
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]]; [_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
} }
_writeRequest = nil; _writeRequest = nil;
objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo); objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
[self _sendDocumentSavedNotification:NO]; [self _sendDocumentSavedNotification:NO];
} }
@@ -563,7 +564,7 @@ var CPDocumentUntitledCount = 0;
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)aData - (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)aData
{ {
var session = aConnection.session; var session = aConnection.session;
// READ // READ
if (aConnection == _readConnection) if (aConnection == _readConnection)
{ {
@@ -575,9 +576,9 @@ var CPDocumentUntitledCount = 0;
{ {
if (session.saveOperation != CPSaveToOperation) if (session.saveOperation != CPSaveToOperation)
[self setFileURL:session.absoluteURL]; [self setFileURL:session.absoluteURL];
_writeRequest = nil; _writeRequest = nil;
objj_msgSend(session.delegate, session.didSaveSelector, self, YES, session.contextInfo); objj_msgSend(session.delegate, session.didSaveSelector, self, YES, session.contextInfo);
[self _sendDocumentSavedNotification:YES]; [self _sendDocumentSavedNotification:YES];
} }
@@ -590,17 +591,17 @@ var CPDocumentUntitledCount = 0;
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError - (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
{ {
var session = aConnection.session; var session = aConnection.session;
if (_readConnection == aConnection) if (_readConnection == aConnection)
objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo); objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
else else
{ {
if (session.saveOperation != CPSaveToOperation) if (session.saveOperation != CPSaveToOperation)
{ {
_changeCount += session.changeCount; _changeCount += session.changeCount;
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]]; [_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
} }
_writeRequest = nil; _writeRequest = nil;
@@ -643,9 +644,9 @@ var CPDocumentUntitledCount = 0;
else if (aChangeType == CPChangeCleared) else if (aChangeType == CPChangeCleared)
_changeCount = 0; _changeCount = 0;
/*else if (aChangeType == CPCHangeReadOtherContents) /*else if (aChangeType == CPCHangeReadOtherContents)
else if (aChangeType == CPChangeAutosaved)*/ else if (aChangeType == CPChangeAutosaved)*/
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]]; [_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
} }
@@ -685,9 +686,9 @@ var CPDocumentUntitledCount = 0;
{ {
if (_hasUndoManager == aFlag) if (_hasUndoManager == aFlag)
return; return;
_hasUndoManager = aFlag; _hasUndoManager = aFlag;
if (!_hasUndoManager) if (!_hasUndoManager)
[self setUndoManager:nil]; [self setUndoManager:nil];
} }
@@ -696,7 +697,7 @@ var CPDocumentUntitledCount = 0;
- (void)_undoManagerWillCloseGroup:(CPNotification)aNotification - (void)_undoManagerWillCloseGroup:(CPNotification)aNotification
{ {
var undoManager = [aNotification object]; var undoManager = [aNotification object];
if ([undoManager isUndoing] || [undoManager isRedoing]) if ([undoManager isUndoing] || [undoManager isRedoing])
return; return;
@@ -723,13 +724,13 @@ var CPDocumentUntitledCount = 0;
- (void)setUndoManager:(CPUndoManager)anUndoManager - (void)setUndoManager:(CPUndoManager)anUndoManager
{ {
var defaultCenter = [CPNotificationCenter defaultCenter]; var defaultCenter = [CPNotificationCenter defaultCenter];
if (_undoManager) if (_undoManager)
{ {
[defaultCenter removeObserver:self [defaultCenter removeObserver:self
name:CPUndoManagerDidUndoChangeNotification name:CPUndoManagerDidUndoChangeNotification
object:_undoManager]; object:_undoManager];
[defaultCenter removeObserver:self [defaultCenter removeObserver:self
name:CPUndoManagerDidRedoChangeNotification name:CPUndoManagerDidRedoChangeNotification
object:_undoManager]; object:_undoManager];
@@ -738,17 +739,17 @@ var CPDocumentUntitledCount = 0;
name:CPUndoManagerWillCloseUndoGroupNotification name:CPUndoManagerWillCloseUndoGroupNotification
object:_undoManager]; object:_undoManager];
} }
_undoManager = anUndoManager; _undoManager = anUndoManager;
if (_undoManager) if (_undoManager)
{ {
[defaultCenter addObserver:self [defaultCenter addObserver:self
selector:@selector(_undoManagerDidUndoChange:) selector:@selector(_undoManagerDidUndoChange:)
name:CPUndoManagerDidUndoChangeNotification name:CPUndoManagerDidUndoChangeNotification
object:_undoManager]; object:_undoManager];
[defaultCenter addObserver:self [defaultCenter addObserver:self
selector:@selector(_undoManagerDidRedoChange:) selector:@selector(_undoManagerDidRedoChange:)
name:CPUndoManagerDidRedoChangeNotification name:CPUndoManagerDidRedoChangeNotification
@@ -774,7 +775,7 @@ var CPDocumentUntitledCount = 0;
return _undoManager; return _undoManager;
} }
/* /*
Implemented as a delegate of a CPWindow Implemented as a delegate of a CPWindow
@ignore @ignore
@@ -803,7 +804,7 @@ var CPDocumentUntitledCount = 0;
[[CPNotificationCenter defaultCenter] [[CPNotificationCenter defaultCenter]
postNotificationName:CPDocumentWillSaveNotification postNotificationName:CPDocumentWillSaveNotification
object:self]; object:self];
[self saveToURL:_fileURL ofType:[self fileType] forSaveOperation:CPSaveOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo]; [self saveToURL:_fileURL ofType:[self fileType] forSaveOperation:CPSaveOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
} }
else else
@@ -861,7 +862,7 @@ var CPDocumentUntitledCount = 0;
[[CPDocumentController sharedDocumentController] removeDocument:self]; [[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)) 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}]; [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); 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]) if (![self isDocumentEdited])
return [aDelegate respondsToSelector:aSelector] && objj_msgSend(aDelegate, aSelector, self, YES, context); return [aDelegate respondsToSelector:aSelector] && objj_msgSend(aDelegate, aSelector, self, YES, context);
+22 -22
View File
@@ -29,7 +29,7 @@
var CPSharedDocumentController = nil; var CPSharedDocumentController = nil;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPDocumentController @class CPDocumentController
This class is responsible for managing an application's open documents. 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. been created yet, it will be created then returned.
@return a CPDocumentController @return a CPDocumentController
*/ */
@@ -49,7 +49,7 @@ var CPSharedDocumentController = nil;
{ {
if (!CPSharedDocumentController) if (!CPSharedDocumentController)
[[self alloc] init]; [[self alloc] init];
return CPSharedDocumentController; return CPSharedDocumentController;
} }
@@ -59,11 +59,11 @@ var CPSharedDocumentController = nil;
- (id)init - (id)init
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_documents = [[CPArray alloc] init]; _documents = [[CPArray alloc] init];
if (!CPSharedDocumentController) if (!CPSharedDocumentController)
CPSharedDocumentController = self; CPSharedDocumentController = self;
@@ -85,16 +85,16 @@ var CPSharedDocumentController = nil;
{ {
var index = 0, var index = 0,
count = [_documents count]; count = [_documents count];
for (; index < count; ++index) for (; index < count; ++index)
{ {
var theDocument = _documents[index]; var theDocument = _documents[index];
if ([[theDocument fileURL] isEqual:aURL]) if ([[theDocument fileURL] isEqual:aURL])
return theDocument; return theDocument;
} }
return nil; return nil;
} }
/*! /*!
@@ -105,10 +105,10 @@ var CPSharedDocumentController = nil;
- (void)openUntitledDocumentOfType:(CPString)aType display:(BOOL)shouldDisplay - (void)openUntitledDocumentOfType:(CPString)aType display:(BOOL)shouldDisplay
{ {
var theDocument = [self makeUntitledDocumentOfType:aType error:nil]; var theDocument = [self makeUntitledDocumentOfType:aType error:nil];
if (theDocument) if (theDocument)
[self addDocument:theDocument]; [self addDocument:theDocument];
if (shouldDisplay) if (shouldDisplay)
{ {
[theDocument makeWindowControllers]; [theDocument makeWindowControllers];
@@ -210,7 +210,7 @@ var CPSharedDocumentController = nil;
return; return;
[aDocument makeWindowControllers]; [aDocument makeWindowControllers];
if ([aContextInfo objectForKey:@"shouldDisplay"]) if ([aContextInfo objectForKey:@"shouldDisplay"])
[aDocument showWindows]; [aDocument showWindows];
} }
@@ -224,7 +224,7 @@ var CPSharedDocumentController = nil;
[self openUntitledDocumentOfType:[[_documentTypes objectAtIndex:0] objectForKey:@"CPBundleTypeName"] display:YES]; [self openUntitledDocumentOfType:[[_documentTypes objectAtIndex:0] objectForKey:@"CPBundleTypeName"] display:YES];
} }
-(void)openDocument:(id)aSender - (void)openDocument:(id)aSender
{ {
var openPanel = [CPOpenPanel openPanel]; var openPanel = [CPOpenPanel openPanel];
@@ -276,17 +276,17 @@ var CPSharedDocumentController = nil;
{ {
var index = 0, var index = 0,
count = _documentTypes.length, count = _documentTypes.length,
extension = [[anAbsoluteURL pathExtension] lowercaseString], extension = [[anAbsoluteURL pathExtension] lowercaseString],
starType = nil; starType = nil;
for (; index < count; ++index) for (; index < count; ++index)
{ {
var documentType = _documentTypes[index], var documentType = _documentTypes[index],
extensions = [documentType objectForKey:@"CFBundleTypeExtensions"], extensions = [documentType objectForKey:@"CFBundleTypeExtensions"],
extensionIndex = 0, extensionIndex = 0,
extensionCount = extensions.length; extensionCount = extensions.length;
for (; extensionIndex < extensionCount; ++extensionIndex) for (; extensionIndex < extensionCount; ++extensionIndex)
{ {
var thisExtension = [extensions[extensionIndex] lowercaseString]; var thisExtension = [extensions[extensionIndex] lowercaseString];
@@ -312,11 +312,11 @@ var CPSharedDocumentController = nil;
for (;i < count; ++i) for (;i < count; ++i)
{ {
var documentType = _documentTypes[i]; var documentType = _documentTypes[i];
if ([documentType objectForKey:@"CPBundleTypeName"] == aType) if ([documentType objectForKey:@"CPBundleTypeName"] == aType)
return documentType; return documentType;
} }
return nil; return nil;
} }
@@ -336,7 +336,7 @@ var CPSharedDocumentController = nil;
@implementation CPDocumentController (Closing) @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 = { var context = {
delegate: aDelegate, delegate: aDelegate,
+100 -38
View File
@@ -20,13 +20,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import <AppKit/CPView.j> @import "CPApplication.j"
@import <AppKit/CPEvent.j> @import "CPEvent.j"
@import <AppKit/CPPasteboard.j> @import "CPImageView.j"
@import <AppKit/CPImageView.j> @import "CPPasteboard.j"
@import "CPView.j"
#import "CoreGraphics/CGGeometry.h" @import "CPWindow.j"
#import "Platform/Platform.h"
CPDragOperationNone = 0, CPDragOperationNone = 0,
@@ -40,29 +39,10 @@ CPDragOperationEvery = -1;
#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window]) #define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
var CPDragServerPreviousEvent = nil, var CPDragServerPreviousEvent = nil,
CPDragServerAutoscrollInterval = nil; CPDragServerPeriodicUpdateInterval = 0.05;
/*
var CPDragServerAutoscroll = function()
{
[CPDragServerSource autoscroll:CPDragServerPreviousEvent];
}
if (CPDragServerAutoscrollInterval === nil) var CPSharedDragServer = nil;
{
if ([CPDragServerSource respondsToSelector:@selector(autoscroll:)])
CPDragServerAutoscrollInterval = setInterval(CPDragServerAutoscroll, 100);
}
CPDragServerPreviousEvent = anEvent;
if (CPDragServerAutoscrollInterval !== nil)
clearInterval(CPDragServerAutoscrollInterval);
CPDragServerAutoscrollInterval = nil;
*/
var CPSharedDragServer = nil;
var CPDragServerSource = nil; var CPDragServerSource = nil;
var CPDragServerDraggingInfo = nil; var CPDragServerDraggingInfo = nil;
@@ -150,10 +130,13 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
CGPoint _draggingLocation; CGPoint _draggingLocation;
id _draggingDestination; id _draggingDestination;
BOOL _draggingDestinationWantsPeriodicUpdates;
CGPoint _startDragLocation; CGPoint _startDragLocation;
BOOL _shouldSlideBack; BOOL _shouldSlideBack;
unsigned _dragOperation; unsigned _dragOperation;
CPTimer _draggingUpdateTimer;
} }
/* /*
@@ -234,6 +217,9 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
- (CPDragOperation)draggingUpdatedInPlatformWindow:(CPPlatformWindow)aPlatformWindow location:(CGPoint)aLocation - (CPDragOperation)draggingUpdatedInPlatformWindow:(CPPlatformWindow)aPlatformWindow location:(CGPoint)aLocation
{ {
[_draggingUpdateTimer invalidate];
_draggingUpdateTimer = nil;
var dragOperation = CPDragOperationCopy; var dragOperation = CPDragOperationCopy;
// We have to convert base to bridge since the drag event comes from the source window, not the drag window. // 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]]; var draggingDestination = [aPlatformWindow _dragHitTest:aLocation pasteboard:[CPDragServerDraggingInfo draggingPasteboard]];
@@ -243,25 +229,89 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
if(draggingDestination !== _draggingDestination) if(draggingDestination !== _draggingDestination)
{ {
if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingExited:)]) if ([_draggingDestination respondsToSelector:@selector(draggingExited:)])
[_draggingDestination draggingExited:CPDragServerDraggingInfo]; [_draggingDestination draggingExited:CPDragServerDraggingInfo];
_draggingDestination = draggingDestination; _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]; dragOperation = [_draggingDestination draggingEntered:CPDragServerDraggingInfo];
} }
else if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingUpdated:)]) else if ([_draggingDestination respondsToSelector:@selector(draggingUpdated:)])
dragOperation = [_draggingDestination draggingUpdated:CPDragServerDraggingInfo]; dragOperation = [_draggingDestination draggingUpdated:CPDragServerDraggingInfo];
if (!_draggingDestination) if (!_draggingDestination)
dragOperation = CPDragOperationNone; 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; 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 - (void)draggingEndedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation operation:(CPDragOperation)anOperation
{ {
[_draggingUpdateTimer invalidate];
_draggingUpdateTimer = nil;
[_draggedView removeFromSuperview]; [_draggedView removeFromSuperview];
if (![CPPlatform supportsDragAndDrop]) if (![CPPlatform supportsDragAndDrop])
@@ -277,8 +327,8 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
- (void)performDragOperationInPlatformWindow:(CPPlatformWindow)aPlatformWindow - (void)performDragOperationInPlatformWindow:(CPPlatformWindow)aPlatformWindow
{ {
if (_draggingDestination && if (_draggingDestination &&
(![_draggingDestination respondsToSelector:@selector(prepareForDragOperation:)] || [_draggingDestination prepareForDragOperation:CPDragServerDraggingInfo]) && (![_draggingDestination respondsToSelector:@selector(prepareForDragOperation:)] || [_draggingDestination prepareForDragOperation:CPDragServerDraggingInfo]) &&
(![_draggingDestination respondsToSelector:@selector(performDragOperation:)] || [_draggingDestination performDragOperation:CPDragServerDraggingInfo]) && (![_draggingDestination respondsToSelector:@selector(performDragOperation:)] || [_draggingDestination performDragOperation:CPDragServerDraggingInfo]) &&
[_draggingDestination respondsToSelector:@selector(concludeDragOperation:)]) [_draggingDestination respondsToSelector:@selector(concludeDragOperation:)])
[_draggingDestination concludeDragOperation:CPDragServerDraggingInfo]; [_draggingDestination concludeDragOperation:CPDragServerDraggingInfo];
@@ -404,13 +454,25 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
// Stop tracking events. // Stop tracking events.
return; return;
} }
else if (type === CPKeyDown)
[self draggingSourceUpdatedWithGlobalLocation:platformWindowLocation]; {
_dragOperation = [self draggingUpdatedInPlatformWindow:platformWindow location:platformWindowLocation]; 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. // If we're not a mouse up, then we're going to want to grab the next event.
[CPApp setTarget:self selector:@selector(trackDragging:) [CPApp setTarget:self selector:@selector(trackDragging:)
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPKeyDownMask
untilDate:nil inMode:0 dequeue:NO]; untilDate:nil inMode:0 dequeue:NO];
} }
+165 -38
View File
@@ -21,8 +21,7 @@
*/ */
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import "CPText.j"
#include "CoreGraphics/CGGeometry.h"
CPLeftMouseDown = 1; CPLeftMouseDown = 1;
@@ -41,7 +40,7 @@ CPAppKitDefined = 13;
CPSystemDefined = 14; CPSystemDefined = 14;
CPApplicationDefined = 15; CPApplicationDefined = 15;
CPPeriodic = 16; CPPeriodic = 16;
CPCursorUpdate = 17; CPCursorUpdate = 17;
CPScrollWheel = 22; CPScrollWheel = 22;
CPOtherMouseDown = 25; CPOtherMouseDown = 25;
CPOtherMouseUp = 26; CPOtherMouseUp = 26;
@@ -52,8 +51,7 @@ CPTouchStart = 28;
CPTouchMove = 29; CPTouchMove = 29;
CPTouchEnd = 30; CPTouchEnd = 30;
CPTouchCancel = 31; CPTouchCancel = 31;
CPAlphaShiftKeyMask = 1 << 16; CPAlphaShiftKeyMask = 1 << 16;
CPShiftKeyMask = 1 << 17; CPShiftKeyMask = 1 << 17;
CPControlKeyMask = 1 << 18; CPControlKeyMask = 1 << 18;
@@ -87,26 +85,102 @@ CPPeriodicMask = 1 << CPPeriodic;
CPScrollWheelMask = 1 << CPScrollWheel; CPScrollWheelMask = 1 << CPScrollWheel;
CPAnyEventMask = 0xffffffff; CPAnyEventMask = 0xffffffff;
CPDOMEventDoubleClick = "dblclick", CPUpArrowFunctionKey = "\uF700";
CPDOMEventMouseDown = "mousedown", CPDownArrowFunctionKey = "\uF701";
CPDOMEventMouseUp = "mouseup", CPLeftArrowFunctionKey = "\uF702";
CPDOMEventMouseMoved = "mousemove", CPRightArrowFunctionKey = "\uF703";
CPDOMEventMouseDragged = "mousedrag", CPF1FunctionKey = "\uF704";
CPDOMEventKeyUp = "keyup", CPF2FunctionKey = "\uF705";
CPDOMEventKeyDown = "keydown", CPF3FunctionKey = "\uF706";
CPDOMEventKeyPress = "keypress"; CPF4FunctionKey = "\uF707";
CPDOMEventCopy = "copy"; CPF5FunctionKey = "\uF708";
CPDOMEventPaste = "paste"; CPF6FunctionKey = "\uF709";
CPDOMEventScrollWheel = "mousewheel"; CPF7FunctionKey = "\uF70A";
CPDOMEventTouchStart = "touchstart"; CPF8FunctionKey = "\uF70B";
CPDOMEventTouchMove = "touchmove"; CPF9FunctionKey = "\uF70C";
CPDOMEventTouchEnd = "touchend"; CPF10FunctionKey = "\uF70D";
CPDOMEventTouchCancel = "touchcancel"; 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, var _CPEventPeriodicEventPeriod = 0,
_CPEventPeriodicEventTimer = nil; _CPEventPeriodicEventTimer = nil,
_CPEventUpperCaseRegex = new RegExp("[A-Z]");
/*! /*!
@ingroup appkit @ingroup appkit
@class CPEvent @class CPEvent
CPEvent encapsulates the details of a Cappuccino keyboard or mouse event. CPEvent encapsulates the details of a Cappuccino keyboard or mouse event.
@@ -155,7 +229,7 @@ var _CPEventPeriodicEventPeriod = 0,
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)repeatKey keyCode:(unsigned short)code characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)repeatKey keyCode:(unsigned short)code
{ {
return [[self alloc] _initKeyEventWithType:anEventType location:aPoint modifierFlags:modifierFlags 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]; characters:characters charactersIgnoringModifiers:unmodCharacters isARepeat:repeatKey keyCode:code];
} }
@@ -173,7 +247,7 @@ var _CPEventPeriodicEventPeriod = 0,
@throws CPInternalInconsistencyException if an invalid event type is provided @throws CPInternalInconsistencyException if an invalid event type is provided
@return the new mouse event @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 timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
{ {
@@ -204,12 +278,12 @@ var _CPEventPeriodicEventPeriod = 0,
} }
/* @ignore */ /* @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 timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_type = anEventType; _type = anEventType;
@@ -222,7 +296,7 @@ var _CPEventPeriodicEventPeriod = 0,
_pressure = aPressure; _pressure = aPressure;
_window = [CPApp windowWithWindowNumber:aWindowNumber]; _window = [CPApp windowWithWindowNumber:aWindowNumber];
} }
return self; return self;
} }
@@ -232,7 +306,7 @@ var _CPEventPeriodicEventPeriod = 0,
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_type = anEventType; _type = anEventType;
@@ -246,7 +320,7 @@ var _CPEventPeriodicEventPeriod = 0,
_keyCode = code; _keyCode = code;
_windowNumber = aWindowNumber; _windowNumber = aWindowNumber;
} }
return self; return self;
} }
@@ -256,7 +330,7 @@ var _CPEventPeriodicEventPeriod = 0,
subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2 subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_type = anEventType; _type = anEventType;
@@ -267,7 +341,7 @@ var _CPEventPeriodicEventPeriod = 0,
_subtype = aSubtype; _subtype = aSubtype;
_data1 = aData1; _data1 = aData1;
_data2 = aData2; _data2 = aData2;
} }
return self; return self;
} }
@@ -445,23 +519,76 @@ var _CPEventPeriodicEventPeriod = 0,
return _deltaZ; 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 - (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? // FIXME: More cases? Space?
return _type === CPKeyDown && return NO;
_modifierFlags & (CPCommandKeyMask | CPControlKeyMask) &&
[_characters length] > 0;
} }
/*! /*!
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 aDelay the number of seconds before the first event
@param aPeriod the length of time in seconds between successive events @param aPeriod the length of time in seconds between successive events
*/ */
+ (void)startPeriodicEventsAfterDelay:(CPTimeInterval)aDelay withPeriod:(CPTimeInterval)aPeriod + (void)startPeriodicEventsAfterDelay:(CPTimeInterval)aDelay withPeriod:(CPTimeInterval)aPeriod
{ {
_CPEventPeriodicEventPeriod = aPeriod; _CPEventPeriodicEventPeriod = aPeriod;
// FIXME: OH TIMERS!!! // FIXME: OH TIMERS!!!
_CPEventPeriodicEventTimer = window.setTimeout(function() { _CPEventPeriodicEventTimer = window.setInterval(_CPEventFirePeriodEvent, aPeriod * 1000.0); }, aDelay * 1000.0); _CPEventPeriodicEventTimer = window.setTimeout(function() { _CPEventPeriodicEventTimer = window.setInterval(_CPEventFirePeriodEvent, aPeriod * 1000.0); }, aDelay * 1000.0);
} }
@@ -473,9 +600,9 @@ var _CPEventPeriodicEventPeriod = 0,
{ {
if (_CPEventPeriodicEventTimer === nil) if (_CPEventPeriodicEventTimer === nil)
return; return;
window.clearTimeout(_CPEventPeriodicEventTimer); window.clearTimeout(_CPEventPeriodicEventTimer);
_CPEventPeriodicEventTimer = nil; _CPEventPeriodicEventTimer = nil;
} }
+1
View File
@@ -22,6 +22,7 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
/*! /*!
@ingroup appkit @ingroup appkit
@class CPFlashMovie @class CPFlashMovie
-1
View File
@@ -23,7 +23,6 @@
@import "CPFlashMovie.j" @import "CPFlashMovie.j"
@import "CPView.j" @import "CPView.j"
#include "Platform/Platform.h"
var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"; 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 * 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 = {}, var _CPFonts = {},
_CPFontSystemFontFace = @"Arial, sans-serif", _CPFontSystemFontFace = @"Arial, sans-serif",
_CPWrapRegExp = new RegExp("\\s*,\\s*", "g"); _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 _CPCreateCSSString(aName, aSize, isBold) (isBold ? @"bold " : @"") + ROUND(aSize) + @"px " + ((aName === _CPFontSystemFontFace) ? aName : (@"\"" + aName.replace(_CPWrapRegExp, '", "') + @"\", " + _CPFontSystemFontFace))
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[_CPCreateCSSString(aName, aSize, isBold)] #define _CPCachedFont(aName, aSize, isBold) _CPFonts[_CPCreateCSSString(aName, aSize, isBold)]
/*! /*!
@ingroup appkit @ingroup appkit
@class CPFont @class CPFont
@@ -38,11 +44,22 @@ var _CPFonts = {},
{ {
CPString _name; CPString _name;
float _size; float _size;
float _ascender;
float _descender;
float _lineHeight;
BOOL _isBold; BOOL _isBold;
CPString _cssString; 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. Returns a font with the specified name and size.
@param aName the name of the font @param aName the name of the font
@@ -89,25 +106,64 @@ var _CPFonts = {},
@ignore @ignore
*/ */
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold - (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_name = aName; _name = aName;
_size = aSize; _size = aSize;
_ascender = 0;
_descender = 0;
_lineHeight = 0;
_isBold = isBold; _isBold = isBold;
_cssString = _CPCreateCSSString(_name, _size, _isBold); _cssString = _CPCreateCSSString(_name, _size, _isBold);
_CPFonts[_cssString] = self; _CPFonts[_cssString] = self;
} }
return 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 - (float)size
{ {
@@ -140,6 +196,15 @@ var _CPFonts = {},
return [CPString stringWithFormat:@"%@ %@ %f pt.", [super description], [self familyName], [self size]]; 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 @end
var CPFontNameKey = @"CPFontNameKey", var CPFontNameKey = @"CPFontNameKey",
+1 -1
View File
@@ -22,7 +22,7 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import <AppKit/CPFont.j> @import "CPFont.j"
var CPSharedFontManager = nil, var CPSharedFontManager = nil,
+29 -15
View File
@@ -70,7 +70,7 @@ function CPPointMake(x, y)
*/ */
function CPRectInset(aRect, dX, dY) 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); aRect.size.width - 2 * dX, aRect.size.height - 2*dY);
} }
@@ -96,13 +96,13 @@ function CPRectIntegral(aRect)
function CPRectIntersection(lhsRect, rhsRect) function CPRectIntersection(lhsRect, rhsRect)
{ {
var intersection = CPRectMake( var intersection = CPRectMake(
Math.max(CPRectGetMinX(lhsRect), CPRectGetMinX(rhsRect)), Math.max(CPRectGetMinX(lhsRect), CPRectGetMinX(rhsRect)),
Math.max(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)), Math.max(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)),
0, 0); 0, 0);
intersection.size.width = Math.min(CPRectGetMaxX(lhsRect), CPRectGetMaxX(rhsRect)) - CPRectGetMinX(intersection); intersection.size.width = Math.min(CPRectGetMaxX(lhsRect), CPRectGetMaxX(rhsRect)) - CPRectGetMinX(intersection);
intersection.size.height = Math.min(CPRectGetMaxY(lhsRect), CPRectGetMaxY(rhsRect)) - CPRectGetMinY(intersection); intersection.size.height = Math.min(CPRectGetMaxY(lhsRect), CPRectGetMaxY(rhsRect)) - CPRectGetMinY(intersection);
return CPRectIsEmpty(intersection) ? CPRectMakeZero() : intersection; return CPRectIsEmpty(intersection) ? CPRectMakeZero() : intersection;
} }
@@ -160,13 +160,13 @@ function CPRectStandardize(aRect)
standardized.origin.x += width; standardized.origin.x += width;
standardized.size.width = -width; standardized.size.width = -width;
} }
if (height < 0.0) if (height < 0.0)
{ {
standardized.origin.y += height; standardized.origin.y += height;
standardized.size.height = -height; standardized.size.height = -height;
} }
return standardized; return standardized;
} }
@@ -183,7 +183,7 @@ function CPRectUnion(lhsRect, rhsRect)
minY = Math.min(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)), minY = Math.min(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)),
maxX = Math.max(CPRectGetMaxX(lhsRect), CPRectGetMaxX(rhsRect)), maxX = Math.max(CPRectGetMaxX(lhsRect), CPRectGetMaxX(rhsRect)),
maxY = Math.max(CPRectGetMaxY(lhsRect), CPRectGetMaxY(rhsRect)); maxY = Math.max(CPRectGetMaxY(lhsRect), CPRectGetMaxY(rhsRect));
return CPRectMake(minX, minY, maxX - minX, maxY - minY); return CPRectMake(minX, minY, maxX - minX, maxY - minY);
} }
@@ -222,8 +222,8 @@ function CPRectContainsPoint(aRect, aPoint)
{ {
return aPoint.x >= CPRectGetMinX(aRect) && return aPoint.x >= CPRectGetMinX(aRect) &&
aPoint.y >= CPRectGetMinY(aRect) && aPoint.y >= CPRectGetMinY(aRect) &&
aPoint.x < CPRectGetMaxX(aRect) && aPoint.x < CPRectGetMaxX(aRect) &&
aPoint.y < CPRectGetMaxY(aRect); aPoint.y < CPRectGetMaxY(aRect);
} }
/*! /*!
@@ -261,7 +261,7 @@ function CPPointEqualToPoint(lhsPoint, rhsPoint)
*/ */
function CPRectEqualToRect(lhsRect, rhsRect) function CPRectEqualToRect(lhsRect, rhsRect)
{ {
return CPPointEqualToPoint(lhsRect.origin, rhsRect.origin) && return CPPointEqualToPoint(lhsRect.origin, rhsRect.origin) &&
CPSizeEqualToSize(lhsRect.size, rhsRect.size); CPSizeEqualToSize(lhsRect.size, rhsRect.size);
} }
@@ -380,6 +380,20 @@ function CPRectIsNull(aRect)
return aRect.size.width <= 0.0 || aRect.size.height <= 0.0; 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. Returns \c YES if the two CGSizes are identical.
@group CGSize @group CGSize
@@ -434,7 +448,7 @@ function CPStringFromRect(aRect)
function CPPointFromString(aString) function CPPointFromString(aString)
{ {
var comma = aString.indexOf(','); var comma = aString.indexOf(',');
return { x:parseFloat(aString.substr(1, comma - 1), 10), y:parseFloat(aString.substring(comma + 1, aString.length), 10) }; 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) function CPSizeFromString(aString)
{ {
var comma = aString.indexOf(','); var comma = aString.indexOf(',');
return { width:parseFloat(aString.substr(1, comma - 1), 10), height:parseFloat(aString.substring(comma + 1, aString.length), 10) }; 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) function CPRectFromString(aString)
{ {
var comma = aString.indexOf(',', aString.indexOf(',') + 1); var comma = aString.indexOf(',', aString.indexOf(',') + 1);
return { origin:CPPointFromString(aString.substr(1, comma - 1)), size:CPSizeFromString(aString.substring(comma + 2, aString.length)) }; 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); 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 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import <Foundation/CPObject.j>
@import "CGContext.j"
var CPGraphicsContextCurrent = nil; var CPGraphicsContextCurrent = nil;
/*! /*!
+9 -6
View File
@@ -28,8 +28,6 @@
@import "CPGeometry.j" @import "CPGeometry.j"
#include "Platform/Platform.h"
CPImageLoadStatusInitialized = 0; CPImageLoadStatusInitialized = 0;
CPImageLoadStatusLoading = 1; CPImageLoadStatusLoading = 1;
@@ -193,6 +191,9 @@ function CPAppKitImage(aFilename, aSize)
var imageOrSize = AppKitImageForNames[aName]; var imageOrSize = AppKitImageForNames[aName];
if (!imageOrSize)
return nil;
if (!imageOrSize.isa) if (!imageOrSize.isa)
{ {
imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize); imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize);
@@ -205,17 +206,19 @@ function CPAppKitImage(aFilename, aSize)
return imageOrSize; return imageOrSize;
} }
- (void)setName:(CPString)aName - (BOOL)setName:(CPString)aName
{ {
if (_name === aName) if (_name === aName)
return; return YES;
if (imagesForNames[aName] === self) if (imagesForNames[aName])
imagesForNames[aName] = nil; return NO;
_name = aName; _name = aName;
imagesForNames[aName] = self; imagesForNames[aName] = self;
return YES;
} }
- (CPString)name - (CPString)name
+99 -18
View File
@@ -26,16 +26,23 @@
@import "CPImage.j" @import "CPImage.j"
@import "CPShadowView.j" @import "CPShadowView.j"
#include "Platform/Platform.h"
#include "Platform/DOM/CPDOMDisplayServer.h"
#include "CoreGraphics/CGGeometry.h"
CPScaleProportionally = 0; CPScaleProportionally = 0;
CPScaleToFit = 1; CPScaleToFit = 1;
CPScaleNone = 2; 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, var LEFT_SHADOW_INSET = 3.0,
RIGHT_SHADOW_INSET = 3.0, RIGHT_SHADOW_INSET = 3.0,
@@ -52,14 +59,22 @@ var LEFT_SHADOW_INSET = 3.0,
*/ */
@implementation CPImageView : CPControl @implementation CPImageView : CPControl
{ {
DOMElement _DOMImageElement; DOMElement _DOMImageElement;
BOOL _hasShadow; BOOL _hasShadow;
CPView _shadowView; 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 - (id)initWithFrame:(CGRect)aFrame
@@ -120,7 +135,7 @@ var LEFT_SHADOW_INSET = 3.0,
var newImage = [self objectValue]; var newImage = [self objectValue];
#if PLATFORM(DOM) #if PLATFORM(DOM)
_DOMImageElement.src = newImage ? [newImage filename] : ""; _DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
#endif #endif
var size = [newImage size]; var size = [newImage size];
@@ -191,6 +206,30 @@ var LEFT_SHADOW_INSET = 3.0,
[self hideOrDisplayContents]; [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 Sets the type of image scaling that should be used to
render the image. render the image.
@@ -318,8 +357,45 @@ var LEFT_SHADOW_INSET = 3.0,
#endif #endif
} }
var x = (boundsWidth - width) / 2.0, var x, y;
y = (boundsHeight - height) / 2.0;
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) #if PLATFORM(DOM)
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y); CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y);
@@ -365,7 +441,7 @@ var LEFT_SHADOW_INSET = 3.0,
return _isEditable; return _isEditable;
} }
- (void)performDragOperation:(CPDraggingInfo)aSender - (BOOL)performDragOperation:(CPDraggingInfo)aSender
{ {
var images = [CPKeyedUnarchiver unarchiveObjectWithData:[[aSender draggingPasteboard] dataForType:CPImagesPboardType]]; var images = [CPKeyedUnarchiver unarchiveObjectWithData:[[aSender draggingPasteboard] dataForType:CPImagesPboardType]];
@@ -374,14 +450,17 @@ var LEFT_SHADOW_INSET = 3.0,
[self setImage:images[0]]; [self setImage:images[0]];
[self sendAction:[self action] to:[self target]]; [self sendAction:[self action] to:[self target]];
} }
return YES;
} }
@end @end
var CPImageViewImageKey = @"CPImageViewImageKey", var CPImageViewImageKey = @"CPImageViewImageKey",
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey", CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey", CPImageViewImageAlignmentKey = @"CPImageViewImageAlignmentKey",
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey"; CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
@implementation CPImageView (CPCoding) @implementation CPImageView (CPCoding)
@@ -414,6 +493,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
#endif #endif
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]]; [self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
[self setImageAlignment:[aCoder decodeIntForKey:CPImageViewImageAlignmentKey]];
if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO) if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO)
[self setEditable:YES]; [self setEditable:YES];
@@ -448,6 +528,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
_subviews = actualSubviews; _subviews = actualSubviews;
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey]; [aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
[aCoder encodeInt:_imageAlignment forKey:CPImageViewImageAlignmentKey];
if (_isEditable) if (_isEditable)
[aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey]; [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 "CPMenuItem.j"
@import "CPPanel.j" @import "CPPanel.j"
#include "../CoreGraphics/CGGeometry.h"
#include "../Platform/Platform.h"
CPMenuDidAddItemNotification = @"CPMenuDidAddItemNotification"; CPMenuDidAddItemNotification = @"CPMenuDidAddItemNotification";
CPMenuDidChangeItemNotification = @"CPMenuDidChangeItemNotification"; CPMenuDidChangeItemNotification = @"CPMenuDidChangeItemNotification";
@@ -50,11 +47,11 @@ var _CPMenuBarVisible = NO,
_CPMenuBarAttributes = nil, _CPMenuBarAttributes = nil,
_CPMenuBarSharedWindow = nil; _CPMenuBarSharedWindow = nil;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPMenu @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. and so a heirarchical structure appears.
*/ */
@implementation CPMenu : CPObject @implementation CPMenu : CPObject
@@ -69,13 +66,13 @@ var _CPMenuBarVisible = NO,
float _minimumWidth; float _minimumWidth;
CPMutableArray _items; CPMutableArray _items;
BOOL _autoenablesItems; BOOL _autoenablesItems;
BOOL _showsStateColumn; BOOL _showsStateColumn;
id _delegate; id _delegate;
CPMenuItem _highlightedIndex; int _highlightedIndex;
_CPMenuWindow _menuWindow; _CPMenuWindow _menuWindow;
} }
@@ -95,7 +92,7 @@ var _CPMenuBarVisible = NO,
{ {
if (_CPMenuBarVisible === menuBarShouldBeVisible) if (_CPMenuBarVisible === menuBarShouldBeVisible)
return; return;
_CPMenuBarVisible = menuBarShouldBeVisible; _CPMenuBarVisible = menuBarShouldBeVisible;
if ([CPPlatform supportsNativeMainMenu]) if ([CPPlatform supportsNativeMainMenu])
@@ -105,13 +102,13 @@ var _CPMenuBarVisible = NO,
{ {
if (!_CPMenuBarSharedWindow) if (!_CPMenuBarSharedWindow)
_CPMenuBarSharedWindow = [[_CPMenuBarWindow alloc] init]; _CPMenuBarSharedWindow = [[_CPMenuBarWindow alloc] init];
[_CPMenuBarSharedWindow setMenu:[CPApp mainMenu]]; [_CPMenuBarSharedWindow setMenu:[CPApp mainMenu]];
[_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle]; [_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle];
[_CPMenuBarSharedWindow setIconImage:_CPMenuBarIconImage]; [_CPMenuBarSharedWindow setIconImage:_CPMenuBarIconImage];
[_CPMenuBarSharedWindow setIconImageAlphaValue:_CPMenuBarIconImageAlphaValue]; [_CPMenuBarSharedWindow setIconImageAlphaValue:_CPMenuBarIconImageAlphaValue];
[_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]]; [_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
[_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]]; [_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]];
[_CPMenuBarSharedWindow setTitleColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleColor"]]; [_CPMenuBarSharedWindow setTitleColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleColor"]];
@@ -120,12 +117,12 @@ var _CPMenuBarVisible = NO,
[_CPMenuBarSharedWindow setHighlightColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightColor"]]; [_CPMenuBarSharedWindow setHighlightColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightColor"]];
[_CPMenuBarSharedWindow setHighlightTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextColor"]]; [_CPMenuBarSharedWindow setHighlightTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextColor"]];
[_CPMenuBarSharedWindow setHighlightTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]]; [_CPMenuBarSharedWindow setHighlightTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]];
[_CPMenuBarSharedWindow orderFront:self]; [_CPMenuBarSharedWindow orderFront:self];
} }
else else
[_CPMenuBarSharedWindow orderOut:self]; [_CPMenuBarSharedWindow orderOut:self];
// FIXME: There must be a better way to do this. // FIXME: There must be a better way to do this.
#if PLATFORM(DOM) #if PLATFORM(DOM)
[[CPPlatformWindow primaryPlatformWindow] resizeEvent:nil]; [[CPPlatformWindow primaryPlatformWindow] resizeEvent:nil];
@@ -159,9 +156,9 @@ var _CPMenuBarVisible = NO,
{ {
if (_CPMenuBarAttributes == attributes) if (_CPMenuBarAttributes == attributes)
return; return;
_CPMenuBarAttributes = [attributes copy]; _CPMenuBarAttributes = [attributes copy];
var textColor = [attributes objectForKey:@"CPMenuBarTextColor"], var textColor = [attributes objectForKey:@"CPMenuBarTextColor"],
titleColor = [attributes objectForKey:@"CPMenuBarTitleColor"], titleColor = [attributes objectForKey:@"CPMenuBarTitleColor"],
textShadowColor = [attributes objectForKey:@"CPMenuBarTextShadowColor"], textShadowColor = [attributes objectForKey:@"CPMenuBarTextShadowColor"],
@@ -169,40 +166,40 @@ var _CPMenuBarVisible = NO,
highlightColor = [attributes objectForKey:@"CPMenuBarHighlightColor"], highlightColor = [attributes objectForKey:@"CPMenuBarHighlightColor"],
highlightTextColor = [attributes objectForKey:@"CPMenuBarHighlightTextColor"], highlightTextColor = [attributes objectForKey:@"CPMenuBarHighlightTextColor"],
highlightTextShadowColor = [attributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]; highlightTextShadowColor = [attributes objectForKey:@"CPMenuBarHighlightTextShadowColor"];
if (!textColor && titleColor) if (!textColor && titleColor)
[_CPMenuBarAttributes setObject:titleColor forKey:@"CPMenuBarTextColor"]; [_CPMenuBarAttributes setObject:titleColor forKey:@"CPMenuBarTextColor"];
else if (textColor && !titleColor) else if (textColor && !titleColor)
[_CPMenuBarAttributes setObject:textColor forKey:@"CPMenuBarTitleColor"]; [_CPMenuBarAttributes setObject:textColor forKey:@"CPMenuBarTitleColor"];
else if (!textColor && !titleColor) 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:@"CPMenuBarTextColor"];
[_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTitleColor"]; [_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTitleColor"];
} }
if (!textShadowColor && titleShadowColor) if (!textShadowColor && titleShadowColor)
[_CPMenuBarAttributes setObject:titleShadowColor forKey:@"CPMenuBarTextShadowColor"]; [_CPMenuBarAttributes setObject:titleShadowColor forKey:@"CPMenuBarTextShadowColor"];
else if (textShadowColor && !titleShadowColor) else if (textShadowColor && !titleShadowColor)
[_CPMenuBarAttributes setObject:textShadowColor forKey:@"CPMenuBarTitleShadowColor"]; [_CPMenuBarAttributes setObject:textShadowColor forKey:@"CPMenuBarTitleShadowColor"];
else if (!textShadowColor && !titleShadowColor) else if (!textShadowColor && !titleShadowColor)
{ {
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTextShadowColor"]; [_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTextShadowColor"];
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTitleShadowColor"]; [_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTitleShadowColor"];
} }
if (!highlightColor) if (!highlightColor)
[_CPMenuBarAttributes setObject:[CPColor colorWithCalibratedRed:94.0/255.0 green:130.0/255.0 blue:186.0/255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"]; [_CPMenuBarAttributes setObject:[CPColor colorWithCalibratedRed:94.0/255.0 green:130.0/255.0 blue:186.0/255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"];
if (!highlightTextColor) if (!highlightTextColor)
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarHighlightTextColor"]; [_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarHighlightTextColor"];
if (!highlightTextShadowColor) if (!highlightTextShadowColor)
[_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarHighlightTextShadowColor"]; [_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarHighlightTextShadowColor"];
if (_CPMenuBarSharedWindow) if (_CPMenuBarSharedWindow)
{ {
[_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]]; [_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
@@ -231,7 +228,7 @@ var _CPMenuBarVisible = NO,
{ {
if (self === [CPApp mainMenu]) if (self === [CPApp mainMenu])
return MENUBAR_HEIGHT; return MENUBAR_HEIGHT;
return 0.0; return 0.0;
} }
@@ -249,18 +246,18 @@ var _CPMenuBarVisible = NO,
- (id)initWithTitle:(CPString)aTitle - (id)initWithTitle:(CPString)aTitle
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_title = aTitle; _title = aTitle;
_items = []; _items = [];
_autoenablesItems = YES; _autoenablesItems = YES;
_showsStateColumn = YES; _showsStateColumn = YES;
[self setMinimumWidth:0]; [self setMinimumWidth:0];
} }
return self; return self;
} }
@@ -287,7 +284,7 @@ var _CPMenuBarVisible = NO,
[aMenuItem setMenu:self]; [aMenuItem setMenu:self];
[_items insertObject:aMenuItem atIndex:anIndex]; [_items insertObject:aMenuItem atIndex:anIndex];
[[CPNotificationCenter defaultCenter] [[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidAddItemNotification postNotificationName:CPMenuDidAddItemNotification
object:self object:self
@@ -306,7 +303,7 @@ var _CPMenuBarVisible = NO,
- (CPMenuItem)insertItemWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent atIndex:(unsigned)anIndex - (CPMenuItem)insertItemWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent atIndex:(unsigned)anIndex
{ {
var item = [[CPMenuItem alloc] initWithTitle:aTitle action:anAction keyEquivalent:aKeyEquivalent]; var item = [[CPMenuItem alloc] initWithTitle:aTitle action:anAction keyEquivalent:aKeyEquivalent];
[self insertItem:item atIndex:anIndex]; [self insertItem:item atIndex:anIndex];
return item; return item;
@@ -351,10 +348,10 @@ var _CPMenuBarVisible = NO,
{ {
if (anIndex < 0 || anIndex >= _items.length) if (anIndex < 0 || anIndex >= _items.length)
return; return;
[_items[anIndex] setMenu:nil]; [_items[anIndex] setMenu:nil];
[_items removeObjectAtIndex:anIndex]; [_items removeObjectAtIndex:anIndex];
[[CPNotificationCenter defaultCenter] [[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidRemoveItemNotification postNotificationName:CPMenuDidRemoveItemNotification
object:self object:self
@@ -369,7 +366,7 @@ var _CPMenuBarVisible = NO,
{ {
if ([aMenuItem menu] != self) if ([aMenuItem menu] != self)
return; return;
[[CPNotificationCenter defaultCenter] [[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidChangeItemNotification postNotificationName:CPMenuDidChangeItemNotification
object:self object:self
@@ -385,10 +382,10 @@ var _CPMenuBarVisible = NO,
- (CPMenuItem)itemWithTag:(int)aTag - (CPMenuItem)itemWithTag:(int)aTag
{ {
var index = [self indexOfItemWithTag:aTag]; var index = [self indexOfItemWithTag:aTag];
if (index == CPNotFound) if (index == CPNotFound)
return nil; return nil;
return _items[index]; return _items[index];
} }
@@ -400,10 +397,10 @@ var _CPMenuBarVisible = NO,
- (CPMenuItem)itemWithTitle:(CPString)aTitle - (CPMenuItem)itemWithTitle:(CPString)aTitle
{ {
var index = [self indexOfItemWithTitle:aTitle]; var index = [self indexOfItemWithTitle:aTitle];
if (index == CPNotFound) if (index == CPNotFound)
return nil; return nil;
return _items[index]; return _items[index];
} }
@@ -442,7 +439,7 @@ var _CPMenuBarVisible = NO,
{ {
if ([aMenuItem menu] !== self) if ([aMenuItem menu] !== self)
return CPNotFound; return CPNotFound;
return [_items indexOfObjectIdenticalTo:aMenuItem]; return [_items indexOfObjectIdenticalTo:aMenuItem];
} }
@@ -455,7 +452,7 @@ var _CPMenuBarVisible = NO,
{ {
var index = 0, var index = 0,
count = _items.length; count = _items.length;
for (; index < count; ++index) for (; index < count; ++index)
if ([_items[index] title] === aTitle) if ([_items[index] title] === aTitle)
return index; return index;
@@ -472,7 +469,7 @@ var _CPMenuBarVisible = NO,
{ {
var index = 0, var index = 0,
count = _items.length; count = _items.length;
for (; index < count; ++index) for (; index < count; ++index)
if ([_items[index] tag] == aTag) if ([_items[index] tag] == aTag)
return index; return index;
@@ -490,11 +487,11 @@ var _CPMenuBarVisible = NO,
{ {
var index = 0, var index = 0,
count = _items.length; count = _items.length;
for (; index < count; ++index) for (; index < count; ++index)
{ {
var item = _items[index]; var item = _items[index];
if ([item target] == aTarget && (!anAction || [item action] == anAction)) if ([item target] == aTarget && (!anAction || [item action] == anAction))
return index; return index;
} }
@@ -511,7 +508,7 @@ var _CPMenuBarVisible = NO,
{ {
var index = 0, var index = 0,
count = _items.length; count = _items.length;
for (; index < count; ++index) for (; index < count; ++index)
if ([[_items[index] representedObject] isEqual:anObject]) if ([[_items[index] representedObject] isEqual:anObject])
return index; return index;
@@ -528,7 +525,7 @@ var _CPMenuBarVisible = NO,
{ {
var index = 0, var index = 0,
count = _items.length; count = _items.length;
for (; index < count; ++index) for (; index < count; ++index)
if ([_items[index] submenu] == aMenu) if ([_items[index] submenu] == aMenu)
return index; return index;
@@ -546,7 +543,7 @@ var _CPMenuBarVisible = NO,
{ {
[aMenuItem setTarget:aMenuItem]; [aMenuItem setTarget:aMenuItem];
[aMenuItem setAction:@selector(submenuAction:)]; [aMenuItem setAction:@selector(submenuAction:)];
[aMenuItem setSubmenu:aMenu]; [aMenuItem setSubmenu:aMenu];
} }
@@ -683,7 +680,7 @@ var _CPMenuBarVisible = NO,
itemIndex = [self indexOfItem:anItem]; itemIndex = [self indexOfItem:anItem];
if (itemIndex === CPNotFound) 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; anItem + " is not present in menu " + self;
} }
@@ -747,6 +744,9 @@ var _CPMenuBarVisible = NO,
} }
// Show it. // Show it.
if ([CPPlatform isBrowser])
[menuWindow setPlatformWindow:[[aView window] platformWindow]];
[menuWindow orderFront:self]; [menuWindow orderFront:self];
// Track it. // Track it.
@@ -781,10 +781,10 @@ var _CPMenuBarVisible = NO,
+ (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont + (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont
{ {
var delegate = [aMenu delegate]; var delegate = [aMenu delegate];
if ([delegate respondsToSelector:@selector(menuWillOpen:)]) if ([delegate respondsToSelector:@selector(menuWillOpen:)])
[delegate menuWillOpen:aMenu]; [delegate menuWillOpen:aMenu];
if (!aFont) if (!aFont)
aFont = [CPFont systemFontOfSize:12.0]; aFont = [CPFont systemFontOfSize:12.0];
@@ -816,6 +816,9 @@ var _CPMenuBarVisible = NO,
[menuWindow setFrameOrigin:CGRectIntersection(unconstrainedFrame, constraintRect).origin]; [menuWindow setFrameOrigin:CGRectIntersection(unconstrainedFrame, constraintRect).origin];
} }
if ([CPPlatform isBrowser])
[menuWindow setPlatformWindow:[[aView window] platformWindow]];
[menuWindow orderFront:self]; [menuWindow orderFront:self];
[[_CPMenuManager sharedMenuManager] [[_CPMenuManager sharedMenuManager]
@@ -932,17 +935,7 @@ var _CPMenuBarVisible = NO,
var item = _items[index], var item = _items[index],
modifierMask = [item keyEquivalentModifierMask]; modifierMask = [item keyEquivalentModifierMask];
if ([item keyEquivalent] === [[item keyEquivalent] uppercaseString]) if ([anEvent _triggersKeyEquivalent:[item keyEquivalent] withModifierMask:[item keyEquivalentModifierMask]])
modifierMask |= CPShiftKeyMask;
if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (modifierMask & CPCommandKeyMask))
{
modifierMask |= CPControlKeyMask;
modifierMask &= ~CPCommandKeyMask;
}
if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) == modifierMask &&
[characters caseInsensitiveCompare:[item keyEquivalent]] == CPOrderedSame)
{ {
if ([item isEnabled]) if ([item isEnabled])
[self performActionForItemAtIndex:index]; [self performActionForItemAtIndex:index];
@@ -950,7 +943,7 @@ var _CPMenuBarVisible = NO,
{ {
//beep? //beep?
} }
return YES; return YES;
} }
@@ -969,7 +962,7 @@ var _CPMenuBarVisible = NO,
- (void)performActionForItemAtIndex:(unsigned)anIndex - (void)performActionForItemAtIndex:(unsigned)anIndex
{ {
var item = _items[anIndex]; var item = _items[anIndex];
[CPApp sendAction:[item action] to:[item target] from:item]; [CPApp sendAction:[item action] to:[item target] from:item];
} }
@@ -1058,7 +1051,7 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_title = [aCoder decodeObjectForKey:CPMenuTitleKey]; _title = [aCoder decodeObjectForKey:CPMenuTitleKey];
@@ -1070,7 +1063,7 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
[self setMinimumWidth:0]; [self setMinimumWidth:0];
} }
return self; return self;
} }
+1 -4
View File
@@ -1,7 +1,4 @@
@import "CPPanel.j"
#include "../CoreGraphics/CGGeometry.h"
#include "../Platform/Platform.h"
@import "_CPMenuWindow.j" @import "_CPMenuWindow.j"
+1 -4
View File
@@ -1,6 +1,3 @@
#include "../CoreGraphics/CGGeometry.h"
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@@ -96,7 +93,7 @@ var SharedMenuManager = nil;
// Close Menu Event. // Close Menu Event.
if (type === CPAppKitDefined) 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]; [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 @@
@import "CPWindow.j"
#include "../CoreGraphics/CGGeometry.h"
var _CPMenuWindowPool = [], var _CPMenuWindowPool = [],
+91 -49
View File
@@ -29,7 +29,8 @@
@import "CPView.j" @import "CPView.j"
@import "_CPMenuItemView.j" @import "_CPMenuItemView.j"
/*!
/*!
@ingroup appkit @ingroup appkit
@class CPMenuItem @class CPMenuItem
@@ -43,39 +44,39 @@
CPString _title; CPString _title;
//CPAttributedString _attributedTitle; //CPAttributedString _attributedTitle;
CPFont _font; CPFont _font;
id _target; id _target;
SEL _action; SEL _action;
BOOL _isEnabled; BOOL _isEnabled;
BOOL _isHidden; BOOL _isHidden;
int _tag; int _tag;
int _state; int _state;
CPImage _image; CPImage _image;
CPImage _alternateImage; CPImage _alternateImage;
CPImage _onStateImage; CPImage _onStateImage;
CPImage _offStateImage; CPImage _offStateImage;
CPImage _mixedStateImage; CPImage _mixedStateImage;
CPMenu _submenu; CPMenu _submenu;
CPMenu _menu; CPMenu _menu;
CPString _keyEquivalent; CPString _keyEquivalent;
unsigned _keyEquivalentModifierMask; unsigned _keyEquivalentModifierMask;
int _mnemonicLocation; int _mnemonicLocation;
BOOL _isAlternate; BOOL _isAlternate;
int _indentationLevel; int _indentationLevel;
CPString _toolTip; CPString _toolTip;
id _representedObject; id _representedObject;
CPView _view; CPView _view;
_CPMenuItemView _menuItemView; _CPMenuItemView _menuItemView;
} }
@@ -94,19 +95,19 @@
- (id)initWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent - (id)initWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_isSeparator = NO; _isSeparator = NO;
_title = aTitle; _title = aTitle;
_action = anAction; _action = anAction;
_isEnabled = YES; _isEnabled = YES;
_tag = 0; _tag = 0;
_state = CPOffState; _state = CPOffState;
_keyEquivalent = aKeyEquivalent || @""; _keyEquivalent = aKeyEquivalent || @"";
_keyEquivalentModifierMask = CPPlatformActionKeyMask; _keyEquivalentModifierMask = CPPlatformActionKeyMask;
@@ -114,7 +115,7 @@
_mnemonicLocation = CPNotFound; _mnemonicLocation = CPNotFound;
} }
return self; return self;
} }
@@ -152,7 +153,7 @@
{ {
if (_isHidden == isHidden) if (_isHidden == isHidden)
return; return;
_isHidden = isHidden; _isHidden = isHidden;
[_menu itemChanged:self]; [_menu itemChanged:self];
@@ -173,9 +174,9 @@
{ {
if (_isHidden) if (_isHidden)
return YES; return YES;
var supermenu = [_menu supermenu]; var supermenu = [_menu supermenu];
if ([[supermenu itemAtIndex:[supermenu indexOfItemWithSubmenu:_menu]] isHiddenOrHasHiddenAncestor]) if ([[supermenu itemAtIndex:[supermenu indexOfItemWithSubmenu:_menu]] isHiddenOrHasHiddenAncestor])
return YES; return YES;
@@ -228,11 +229,11 @@
if (_title == aTitle) if (_title == aTitle)
return; return;
_title = aTitle; _title = aTitle;
[_menuItemView setDirty]; [_menuItemView setDirty];
[_menu itemChanged:self]; [_menu itemChanged:self];
} }
@@ -260,11 +261,11 @@
{ {
if (_font == aFont) if (_font == aFont)
return; return;
_font = aFont; _font = aFont;
[_menu itemChanged:self]; [_menu itemChanged:self];
[_menuItemView setDirty]; [_menuItemView setDirty];
} }
@@ -316,9 +317,9 @@ CPOffState
{ {
if (_state == aState) if (_state == aState)
return; return;
_state = aState; _state = aState;
[_menu itemChanged:self]; [_menu itemChanged:self];
[_menuItemView setDirty]; [_menuItemView setDirty];
@@ -346,11 +347,11 @@ CPOffState
{ {
if (_image == anImage) if (_image == anImage)
return; return;
_image = anImage; _image = anImage;
[_menuItemView setDirty]; [_menuItemView setDirty];
[_menu itemChanged:self]; [_menu itemChanged:self];
} }
@@ -388,7 +389,7 @@ CPOffState
{ {
if (_onStateImage == anImage) if (_onStateImage == anImage)
return; return;
_onStateImage = anImage; _onStateImage = anImage;
[_menu itemChanged:self]; [_menu itemChanged:self];
} }
@@ -409,7 +410,7 @@ CPOffState
{ {
if (_offStateImage == anImage) if (_offStateImage == anImage)
return; return;
_offStateImage = anImage; _offStateImage = anImage;
[_menu itemChanged:self]; [_menu itemChanged:self];
} }
@@ -430,7 +431,7 @@ CPOffState
{ {
if (_mixedStateImage == anImage) if (_mixedStateImage == anImage)
return; return;
_mixedStateImage = anImage; _mixedStateImage = anImage;
[_menu itemChanged:self]; [_menu itemChanged:self];
} }
@@ -591,7 +592,8 @@ CPControlKeyMask
return @""; return @"";
var string = _keyEquivalent.toUpperCase(), var string = _keyEquivalent.toUpperCase(),
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || string === _keyEquivalent; needsShift = _keyEquivalentModifierMask & CPShiftKeyMask ||
(string === _keyEquivalent && _keyEquivalent.toLowerCase() !== _keyEquivalent.toUpperCase());
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem)) if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
{ {
@@ -648,14 +650,14 @@ CPControlKeyMask
- (void)setTitleWithMnemonicLocation:(CPString)aTitle - (void)setTitleWithMnemonicLocation:(CPString)aTitle
{ {
var location = [aTitle rangeOfString:@"&"].location; var location = [aTitle rangeOfString:@"&"].location;
if (location == CPNotFound) if (location == CPNotFound)
[self setTitle:aTitle]; [self setTitle:aTitle];
else else
{ {
[self setTitle:[aTitle substringToIndex:location] + [aTitle substringFromIndex:location + 1]]; [self setTitle:[aTitle substringToIndex:location] + [aTitle substringFromIndex:location + 1]];
[self setMnemonicLocation:location]; [self setMnemonicLocation:location];
} }
} }
/*! /*!
@@ -696,7 +698,7 @@ CPControlKeyMask
{ {
if (aLevel < 0) if (aLevel < 0)
[CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than or equal to 0."]; [CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than or equal to 0."];
_indentationLevel = MIN(15, aLevel); _indentationLevel = MIN(15, aLevel);
} }
@@ -755,11 +757,11 @@ CPControlKeyMask
{ {
if (_view === aView) if (_view === aView)
return; return;
_view = aView; _view = aView;
[_menuItemView setDirty]; [_menuItemView setDirty];
[_menu itemChanged:self]; [_menu itemChanged:self];
} }
@@ -781,7 +783,48 @@ CPControlKeyMask
return [[self menu] highlightedItem] == self; 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 @ignore
@@ -790,7 +833,7 @@ CPControlKeyMask
{ {
if (!_menuItemView) if (!_menuItemView)
_menuItemView = [[_CPMenuItemView alloc] initWithFrame:CGRectMakeZero() forMenuItem:self]; _menuItemView = [[_CPMenuItemView alloc] initWithFrame:CGRectMakeZero() forMenuItem:self];
return _menuItemView; return _menuItemView;
} }
@@ -844,15 +887,15 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_isSeparator = [aCoder containsValueForKey:CPMenuItemIsSeparatorKey] && [aCoder decodeBoolForKey:CPMenuItemIsSeparatorKey]; _isSeparator = [aCoder containsValueForKey:CPMenuItemIsSeparatorKey] && [aCoder decodeBoolForKey:CPMenuItemIsSeparatorKey];
_title = [aCoder decodeObjectForKey:CPMenuItemTitleKey]; _title = [aCoder decodeObjectForKey:CPMenuItemTitleKey];
// _font; // _font;
_target = [aCoder decodeObjectForKey:CPMenuItemTargetKey]; _target = [aCoder decodeObjectForKey:CPMenuItemTargetKey];
_action = [aCoder decodeObjectForKey:CPMenuItemActionKey]; _action = [aCoder decodeObjectForKey:CPMenuItemActionKey];
@@ -860,7 +903,6 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
_isHidden = DEFAULT_VALUE(CPMenuItemIsHiddenKey, NO); _isHidden = DEFAULT_VALUE(CPMenuItemIsHiddenKey, NO);
_tag = DEFAULT_VALUE(CPMenuItemTagKey, 0); _tag = DEFAULT_VALUE(CPMenuItemTagKey, 0);
_state = DEFAULT_VALUE(CPMenuItemStateKey, CPOffState); _state = DEFAULT_VALUE(CPMenuItemStateKey, CPOffState);
// int _state;
_image = DEFAULT_VALUE(CPMenuItemImageKey, nil); _image = DEFAULT_VALUE(CPMenuItemImageKey, nil);
_alternateImage = DEFAULT_VALUE(CPMenuItemAlternateImageKey, nil); _alternateImage = DEFAULT_VALUE(CPMenuItemAlternateImageKey, nil);
@@ -887,7 +929,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
_representedObject = DEFAULT_VALUE(CPMenuItemRepresentedObjectKey, nil); _representedObject = DEFAULT_VALUE(CPMenuItemRepresentedObjectKey, nil);
_view = DEFAULT_VALUE(CPMenuItemViewKey, nil); _view = DEFAULT_VALUE(CPMenuItemViewKey, nil);
} }
return self; return self;
} }
@@ -901,11 +943,11 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
[aCoder encodeBool:_isSeparator forKey:CPMenuItemIsSeparatorKey]; [aCoder encodeBool:_isSeparator forKey:CPMenuItemIsSeparatorKey];
[aCoder encodeObject:_title forKey:CPMenuItemTitleKey]; [aCoder encodeObject:_title forKey:CPMenuItemTitleKey];
[aCoder encodeObject:_target forKey:CPMenuItemTargetKey]; [aCoder encodeObject:_target forKey:CPMenuItemTargetKey];
[aCoder encodeObject:_action forKey:CPMenuItemActionKey]; [aCoder encodeObject:_action forKey:CPMenuItemActionKey];
ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES); ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES);
ENCODE_IFNOT(CPMenuItemIsHiddenKey, _isHidden, NO); ENCODE_IFNOT(CPMenuItemIsHiddenKey, _isHidden, NO);
ENCODE_IFNOT(CPMenuItemTagKey, _tag, 0); ENCODE_IFNOT(CPMenuItemTagKey, _tag, 0);
@@ -913,7 +955,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
ENCODE_IFNOT(CPMenuItemImageKey, _image, nil); ENCODE_IFNOT(CPMenuItemImageKey, _image, nil);
ENCODE_IFNOT(CPMenuItemAlternateImageKey, _alternateImage, nil); ENCODE_IFNOT(CPMenuItemAlternateImageKey, _alternateImage, nil);
ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil); ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil);
ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil); ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil);
@@ -1,3 +1,6 @@
@import "CPView.j"
var HORIZONTAL_MARGIN = 8.0, var HORIZONTAL_MARGIN = 8.0,
SUBMENU_INDICATOR_MARGIN = 3.0, SUBMENU_INDICATOR_MARGIN = 3.0,
VERTICAL_MARGIN = 4.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 = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(HORIZONTAL_MARGIN, 0.0, 0.0, 0.0)];
[_imageAndTextView setImagePosition:CPImageLeft]; [_imageAndTextView setImagePosition:CPImageLeft];
[_imageAndTextView setImageOffset:3.0];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)]; [_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[_imageAndTextView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin]; [_imageAndTextView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
+1 -1
View File
@@ -1,5 +1,5 @@
@import <AppKit/CPView.j> @import "CPView.j"
@implementation _CPMenuItemSeparatorView : CPView @implementation _CPMenuItemSeparatorView : CPView
+11 -5
View File
@@ -1,3 +1,6 @@
@import "CPControl.j"
var LEFT_MARGIN = 3.0, var LEFT_MARGIN = 3.0,
RIGHT_MARGIN = 14.0 + 3.0, RIGHT_MARGIN = 14.0 + 3.0,
STATE_COLUMN_WIDTH = 14.0, STATE_COLUMN_WIDTH = 14.0,
@@ -39,7 +42,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
SUBMENU_INDICATOR_COLOR = [CPColor grayColor]; 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]; _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]; var bundle = [CPBundle bundleForClass:self];
@@ -257,10 +260,13 @@ var SUBMENU_INDICATOR_COLOR = nil,
[_keyEquivalentView setTextShadowColor:[self textShadowColor]]; [_keyEquivalentView setTextShadowColor:[self textShadowColor]];
} }
if (shouldHighlight) if ([[_menuItem menu] showsStateColumn])
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil]; {
else if (shouldHighlight)
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil]; [_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
else
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
}
} }
@end @end
+4 -2
View File
@@ -1,4 +1,6 @@
@import <AppKit/CPControl.j>
@import "_CPMenuItemSeparatorView.j" @import "_CPMenuItemSeparatorView.j"
@import "_CPMenuItemStandardView.j" @import "_CPMenuItemStandardView.j"
@import "_CPMenuItemMenuBarView.j" @import "_CPMenuItemMenuBarView.j"
@@ -43,7 +45,7 @@ var _CPMenuItemSelectionColor = nil,
return; return;
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0]; _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]; var bundle = [CPBundle bundleForClass:self];
@@ -252,4 +254,4 @@ var _CPMenuItemSelectionColor = nil,
CGContextFillPath(context); 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 @implementation CPOpenPanel : CPPanel
+371 -125
View File
@@ -23,8 +23,6 @@
@import "CPTableColumn.j" @import "CPTableColumn.j"
@import "CPTableView.j" @import "CPTableView.j"
#include "CoreGraphics/CGGeometry.h"
CPOutlineViewColumnDidMoveNotification = @"CPOutlineViewColumnDidMoveNotification"; CPOutlineViewColumnDidMoveNotification = @"CPOutlineViewColumnDidMoveNotification";
CPOutlineViewColumnDidResizeNotification = @"CPOutlineViewColumnDidResizeNotification"; CPOutlineViewColumnDidResizeNotification = @"CPOutlineViewColumnDidResizeNotification";
@@ -50,12 +48,30 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_ = 1 << 10; CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_ = 1 << 10;
var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ = 1 << 1, var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ = 1 << 1,
CPOutlineViewDelegate_outlineView_shouldSelectItem_ = 1 << 2, CPOutlineViewDelegate_outlineView_didClickTableColumn_ = 1 << 2,
CPOutlineViewDelegate_outlineView_heightOfRowByItem_ = 1 << 3, CPOutlineViewDelegate_outlineView_didDragTableColumn_ = 1 << 3,
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ = 1 << 4, CPOutlineViewDelegate_outlineView_heightOfRowByItem_ = 1 << 4,
CPOutlineViewDelegate_outlineView_isGroupItem_ = 1 << 5; 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; CPOutlineViewDropOnItemIndex = -1;
@@ -79,12 +95,14 @@ CPOutlineViewDropOnItemIndex = -1;
CPArray _disclosureControlsForRows; CPArray _disclosureControlsForRows;
CPData _disclosureControlData; CPData _disclosureControlData;
CPArray _disclosureControlQueue; CPArray _disclosureControlQueue;
BOOL _shouldRetargetItem; BOOL _shouldRetargetItem;
id _retargetedItem; id _retargetedItem;
BOOL _shouldRetargetChildIndex; BOOL _shouldRetargetChildIndex;
CPInteger _retargedChildIndex; CPInteger _retargedChildIndex;
CPTimer _dragHoverTimer;
id _dropItem;
} }
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
@@ -105,9 +123,10 @@ CPOutlineViewDropOnItemIndex = -1;
_retargetedItem = nil; _retargetedItem = nil;
_shouldRetargetItem = NO; _shouldRetargetItem = NO;
_retargedChildIndex = nil; _retargedChildIndex = nil;
_shouldRetargetChildIndex = NO; _shouldRetargetChildIndex = NO;
_startHoverTime = nil;
[self setIndentationPerLevel:16.0]; [self setIndentationPerLevel:16.0];
[self setIndentationMarkerFollowsDataView:YES]; [self setIndentationMarkerFollowsDataView:YES];
@@ -213,7 +232,7 @@ CPOutlineViewDropOnItemIndex = -1;
- (void)expandItem:(id)anItem expandChildren:(BOOL)shouldExpandChildren - (void)expandItem:(id)anItem expandChildren:(BOOL)shouldExpandChildren
{ {
var itemInfo = null; var itemInfo = null;
if (!anItem) if (!anItem)
itemInfo = _rootItemInfo; itemInfo = _rootItemInfo;
else else
@@ -221,15 +240,21 @@ CPOutlineViewDropOnItemIndex = -1;
if (!itemInfo) if (!itemInfo)
return; return;
itemInfo.isExpanded = YES; // to prevent items which are already expanded from firing notifications
[self reloadItem:anItem reloadChildren:YES]; if (!itemInfo.isExpanded)
{
[self _noteItemWillExpand:anItem];
itemInfo.isExpanded = YES;
[self _noteItemDidExpand:anItem];
[self reloadItem:anItem reloadChildren:YES];
}
if (shouldExpandChildren) if (shouldExpandChildren)
{ {
var children = itemInfo.children, var children = itemInfo.children,
childIndex = children.length; childIndex = children.length;
while (childIndex--) while (childIndex--)
[self expandItem:children[childIndex] expandChildren:YES]; [self expandItem:children[childIndex] expandChildren:YES];
} }
@@ -248,7 +273,9 @@ CPOutlineViewDropOnItemIndex = -1;
if (!itemInfo.isExpanded) if (!itemInfo.isExpanded)
return; return;
[self _noteItemWillCollapse:anItem];
itemInfo.isExpanded = NO; itemInfo.isExpanded = NO;
[self _noteItemDidCollapse:anItem];
[self reloadItem:anItem reloadChildren:YES]; [self reloadItem:anItem reloadChildren:YES];
} }
@@ -363,7 +390,7 @@ CPOutlineViewDropOnItemIndex = -1;
return nil; return nil;
var parent = itemInfo.parent; var parent = itemInfo.parent;
// Check if the parent is the root item because we never return the actual root item // Check if the parent is the root item because we never return the actual root item
if (itemInfo[[parent UID]] === _rootItemInfo) if (itemInfo[[parent UID]] === _rootItemInfo)
parent = nil; parent = nil;
@@ -382,43 +409,14 @@ CPOutlineViewDropOnItemIndex = -1;
return frame; 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 [super _performSelection:select forRow:rowIndex context:context];
var previousSelectedRows = [];
[[self selectedRowIndexes] getIndexes:previousSelectedRows maxCount:-1 inIndexRange:nil]; var control = _disclosureControlsForRows[rowIndex],
selector = select ? @"setThemeState:" : @"unsetThemeState:";
var index = [previousSelectedRows count];
while (index--) [control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected];
{
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];
}
} }
- (void)setDelegate:(id)aDelegate - (void)setDelegate:(id)aDelegate
@@ -453,25 +451,76 @@ CPOutlineViewDropOnItemIndex = -1;
removeObserver:_outlineViewDelegate removeObserver:_outlineViewDelegate
name:CPOutlineViewSelectionIsChangingNotification name:CPOutlineViewSelectionIsChangingNotification
object:self]; 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; _outlineViewDelegate = aDelegate;
_implementedOutlineViewDelegateMethods = 0; _implementedOutlineViewDelegateMethods = 0;
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:dataViewForTableColumn:item:)]) var delegateMethods = [
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_; CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ , @selector(outlineView:dataViewForTableColumn:item:),
CPOutlineViewDelegate_outlineView_didClickTableColumn_ , @selector(outlineView:didClickTableColumn:),
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:shouldSelectItem:)]) CPOutlineViewDelegate_outlineView_didDragTableColumn_ , @selector(outlineView:didDragTableColumn:),
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_shouldSelectItem_; CPOutlineViewDelegate_outlineView_heightOfRowByItem_ , @selector(outlineView:heightOfRowByItem:),
CPOutlineViewDelegate_outlineView_isGroupItem_ , @selector(outlineView:isGroupItem:),
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:heightOfRowByItem:)]) CPOutlineViewDelegate_outlineView_mouseDownInHeaderOfTableColumn_ , @selector(outlineView:mouseDownInHeaderOfTableColumn:),
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_heightOfRowByItem_; 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:)]) for (var i=0; i < delegateCount; i += 2)
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_; {
var bitMask = delegateMethods[i],
selector = delegateMethods[i+1];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:isGroupItem:)]) if ([_outlineViewDelegate respondsToSelector:selector])
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_isGroupItem_; _implementedOutlineViewDelegateMethods |= bitMask;
}
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidMove:)]) if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidMove:)])
[defaultCenter [defaultCenter
@@ -500,6 +549,36 @@ CPOutlineViewDropOnItemIndex = -1;
selector:@selector(outlineViewSelectionIsChanging:) selector:@selector(outlineViewSelectionIsChanging:)
name:CPOutlineViewSelectionIsChangingNotification name:CPOutlineViewSelectionIsChangingNotification
object:self]; 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 - (id)delegate
@@ -534,18 +613,63 @@ CPOutlineViewDropOnItemIndex = -1;
- (void)setDropItem:(id)theItem dropChildIndex:(int)theIndex - (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; _retargetedItem = theItem;
_shouldRetargetItem = YES; _shouldRetargetItem = YES;
_retargedChildIndex = theIndex; _retargedChildIndex = theIndex;
_shouldRetargetChildIndex = YES; _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 - (id)_parentItemForUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex atMouseOffset:(CPPoint)theOffset
{ {
if (_shouldRetargetItem) if (_shouldRetargetItem)
return _retargetedItem; return _retargetedItem;
var lowerLevel = [self levelForRow:theLowerRowIndex] var lowerLevel = [self levelForRow:theLowerRowIndex]
upperItem = [self itemAtRow:theUpperRowIndex]; upperItem = [self itemAtRow:theUpperRowIndex];
upperLevel = [self levelForItem:upperItem]; upperLevel = [self levelForItem:upperItem];
@@ -564,7 +688,7 @@ CPOutlineViewDropOnItemIndex = -1;
// Check the next parent // Check the next parent
upperItem = [self parentForItem:upperItem]; upperItem = [self parentForItem:upperItem];
} }
return [self parentForItem:[self itemAtRow:theLowerRowIndex]]; return [self parentForItem:[self itemAtRow:theLowerRowIndex]];
} }
@@ -574,10 +698,10 @@ CPOutlineViewDropOnItemIndex = -1;
var rect = [super _rectForDropHighlightViewBetweenUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex offset:theOffset], var rect = [super _rectForDropHighlightViewBetweenUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex offset:theOffset],
parentItem = [self _parentItemForUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex atMouseOffset:theOffset], parentItem = [self _parentItemForUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex atMouseOffset:theOffset],
level = [self levelForItem:parentItem]; 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 rect.size.width -= rect.origin.x; // This assumes that the x returned by super is zero
return rect; return rect;
} }
@@ -619,6 +743,8 @@ CPOutlineViewDropOnItemIndex = -1;
_disclosureControlsForRows[row] = control; _disclosureControlsForRows[row] = control;
[control setState:[self isItemExpanded:item] ? CPOnState : CPOffState]; [control setState:[self isItemExpanded:item] ? CPOnState : CPOffState];
var selector = [self isRowSelected:row] ? @"setThemeState:" : @"unsetThemeState:";
[control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected];
[control setFrame:frame]; [control setFrame:frame];
[self addSubview:control]; [self addSubview:control];
@@ -709,9 +835,41 @@ CPOutlineViewDropOnItemIndex = -1;
userInfo:nil]; 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 @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) var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
{ {
if (!anItem) if (!anItem)
@@ -724,55 +882,55 @@ var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
dataSource = _outlineViewDataSource, dataSource = _outlineViewDataSource,
itemUID = [anItem UID], itemUID = [anItem UID],
itemInfo = itemInfosForItems[itemUID]; itemInfo = itemInfosForItems[itemUID];
// If we're not in the tree, then just bail. // If we're not in the tree, then just bail.
if (!itemInfo) if (!itemInfo)
return []; return [];
// See if the item itself can be swapped out. // See if the item itself can be swapped out.
var parent = itemInfo.parent, var parent = itemInfo.parent,
parentItemInfo = parent ? itemInfosForItems[[parent UID]] : _rootItemInfo, parentItemInfo = parent ? itemInfosForItems[[parent UID]] : _rootItemInfo,
parentChildren = parentItemInfo.children, parentChildren = parentItemInfo.children,
index = [parentChildren indexOfObjectIdenticalTo:anItem], index = [parentChildren indexOfObjectIdenticalTo:anItem],
newItem = [dataSource outlineView:anOutlineView child:index ofItem:parent]; newItem = [dataSource outlineView:anOutlineView child:index ofItem:parent];
if (anItem !== newItem) if (anItem !== newItem)
{ {
itemInfosForItems[[anItem UID]] = nil; itemInfosForItems[[anItem UID]] = nil;
itemInfosForItems[[newItem UID]] = itemInfo; itemInfosForItems[[newItem UID]] = itemInfo;
parentChildren[index] = newItem; parentChildren[index] = newItem;
_itemsForRows[itemInfo.row] = newItem; _itemsForRows[itemInfo.row] = newItem;
} }
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem]; itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem];
itemInfo.isExpanded = itemInfo.isExpandable && itemInfo.isExpanded; 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) var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem, /*BOOL*/ isIntermediate)
{ {
with(anOutlineView) with(anOutlineView)
{ {
var itemInfosForItems = _itemInfosForItems, var itemInfosForItems = _itemInfosForItems,
dataSource = _outlineViewDataSource; dataSource = _outlineViewDataSource;
if (!anItem) if (!anItem)
var itemInfo = _rootItemInfo; var itemInfo = _rootItemInfo;
else else
{ {
// Get the existing info if it exists. // Get the existing info if it exists.
var itemUID = [anItem UID], var itemUID = [anItem UID],
itemInfo = itemInfosForItems[itemUID]; itemInfo = itemInfosForItems[itemUID];
// If we're not in the tree, then just bail. // If we're not in the tree, then just bail.
if (!itemInfo) if (!itemInfo)
return []; return [];
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:anItem]; itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:anItem];
// If we were previously expanded, but now no longer expandable, "de-expand". // If we were previously expanded, but now no longer expandable, "de-expand".
// NOTE: we are *not* collapsing, thus no notification is posted. // NOTE: we are *not* collapsing, thus no notification is posted.
if (!itemInfo.isExpandable && itemInfo.isExpanded) if (!itemInfo.isExpandable && itemInfo.isExpanded)
@@ -781,72 +939,72 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
itemInfo.children = []; itemInfo.children = [];
} }
} }
// The root item does not count as a descendant. // The root item does not count as a descendant.
var weight = itemInfo.weight, var weight = itemInfo.weight,
descendants = anItem ? [anItem] : []; descendants = anItem ? [anItem] : [];
if (itemInfo.isExpanded && (!(_implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_) || if (itemInfo.isExpanded && (!(_implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_) ||
![dataSource outlineView:anOutlineView shouldDeferDisplayingChildrenOfItem:anItem])) ![dataSource outlineView:anOutlineView shouldDeferDisplayingChildrenOfItem:anItem]))
{ {
var index = 0, var index = 0,
count = [dataSource outlineView:anOutlineView numberOfChildrenOfItem:anItem], count = [dataSource outlineView:anOutlineView numberOfChildrenOfItem:anItem],
level = itemInfo.level + 1; level = itemInfo.level + 1;
itemInfo.children = []; itemInfo.children = [];
for (; index < count; ++index) for (; index < count; ++index)
{ {
var childItem = [dataSource outlineView:anOutlineView child:index ofItem:anItem], var childItem = [dataSource outlineView:anOutlineView child:index ofItem:anItem],
childItemInfo = itemInfosForItems[[childItem UID]]; childItemInfo = itemInfosForItems[[childItem UID]];
if (!childItemInfo) if (!childItemInfo)
{ {
childItemInfo = { isExpanded:NO, isExpandable:NO, children:[], weight:1 }; childItemInfo = { isExpanded:NO, isExpandable:NO, children:[], weight:1 };
itemInfosForItems[[childItem UID]] = childItemInfo; itemInfosForItems[[childItem UID]] = childItemInfo;
} }
itemInfo.children[index] = childItem; itemInfo.children[index] = childItem;
var childDescendants = _loadItemInfoForItem(anOutlineView, childItem, YES); var childDescendants = _loadItemInfoForItem(anOutlineView, childItem, YES);
childItemInfo.parent = anItem; childItemInfo.parent = anItem;
childItemInfo.level = level; childItemInfo.level = level;
descendants = descendants.concat(childDescendants); descendants = descendants.concat(childDescendants);
} }
} }
itemInfo.weight = descendants.length; itemInfo.weight = descendants.length;
if (!isIntermediate) if (!isIntermediate)
{ {
// row = -1 is the root item, so just go to row 0 since it is ignored. // row = -1 is the root item, so just go to row 0 since it is ignored.
var index = MAX(itemInfo.row, 0), var index = MAX(itemInfo.row, 0),
itemsForRows = _itemsForRows; itemsForRows = _itemsForRows;
descendants.unshift(index, weight); descendants.unshift(index, weight);
itemsForRows.splice.apply(itemsForRows, descendants); itemsForRows.splice.apply(itemsForRows, descendants);
var count = itemsForRows.length; var count = itemsForRows.length;
for (; index < count; ++index) for (; index < count; ++index)
itemInfosForItems[[itemsForRows[index] UID]].row = index; itemInfosForItems[[itemsForRows[index] UID]].row = index;
var deltaWeight = itemInfo.weight - weight; var deltaWeight = itemInfo.weight - weight;
if (deltaWeight !== 0) if (deltaWeight !== 0)
{ {
var parent = itemInfo.parent; var parent = itemInfo.parent;
while (parent) while (parent)
{ {
var parentItemInfo = itemInfosForItems[[parent UID]]; var parentItemInfo = itemInfosForItems[[parent UID]];
parentItemInfo.weight += deltaWeight; parentItemInfo.weight += deltaWeight;
parent = parentItemInfo.parent; parent = parentItemInfo.parent;
} }
if (anItem) if (anItem)
_rootItemInfo.weight += deltaWeight; _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]]; 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 - (BOOL)tableView:(CPTableView)aTableColumn writeRowsWithIndexes:(CPIndexSet)theIndexes toPasteboard:(CPPasteboard)thePasteboard
{ {
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_)) if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_))
return NO; return NO;
var rowIndexes = []; var rowIndexes = [];
[theIndexes getIndexes:rowIndexes maxCount:[theIndexes count] inIndexRange:nil]; [theIndexes getIndexes:rowIndexes maxCount:[theIndexes count] inIndexRange:nil];
var rowIndex = [rowIndexes count], var rowIndex = [rowIndexes count],
items = []; items = [];
while (rowIndex--) while (rowIndex--)
[items addObject:[_outlineView itemAtRow:[rowIndexes objectAtIndex:rowIndex]]]; [items addObject:[_outlineView itemAtRow:[rowIndexes objectAtIndex:rowIndex]]];
return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard]; return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard];
} }
@@ -901,15 +1066,15 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
{ {
if (_outlineView._shouldRetargetChildIndex) if (_outlineView._shouldRetargetChildIndex)
return _outlineView._retargedChildIndex; return _outlineView._retargedChildIndex;
var childIndex = CPNotFound; var childIndex = CPNotFound;
if (theDropOperation === CPTableViewDropAbove) if (theDropOperation === CPTableViewDropAbove)
{ {
var parentItem = [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset], var parentItem = [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset],
itemInfo = (parentItem !== nil) ? _outlineView._itemInfosForItems[[parentItem UID]] : _outlineView._rootItemInfo, itemInfo = (parentItem !== nil) ? _outlineView._itemInfosForItems[[parentItem UID]] : _outlineView._rootItemInfo,
children = itemInfo.children; children = itemInfo.children;
childIndex = [children indexOfObject:[_outlineView itemAtRow:theRow]]; childIndex = [children indexOfObject:[_outlineView itemAtRow:theRow]];
if (childIndex === CPNotFound) if (childIndex === CPNotFound)
@@ -924,12 +1089,12 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
- (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)theOffset - (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)theOffset
{ {
if (theDropOperation === CPTableViewDropAbove) 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]; 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 proposedRow:(int)theRow proposedDropOperation:(CPTableViewDropOperation)theOperation
{ {
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_)) if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_))
@@ -943,21 +1108,21 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
_outlineView._shouldRetargetChildIndex = NO; _outlineView._shouldRetargetChildIndex = NO;
var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil], 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]; childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
return [_outlineView._outlineViewDataSource outlineView:_outlineView validateDrop:theInfo proposedItem:parentItem proposedChildIndex:childIndex]; 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 - (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id <CPDraggingInfo>)theInfo row:(int)theRow dropOperation:(CPTableViewDropOperation)theOperation
{ {
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_)) if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_))
return NO; return NO;
var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil], 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]; childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
_outlineView._retargetedItem = nil; _outlineView._retargetedItem = nil;
_outlineView._shouldRetargetItem = NO; _outlineView._shouldRetargetItem = NO;
@@ -987,15 +1152,15 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
- (CPView)tableView:(CPTableView)theTableView dataViewForTableColumn:(CPTableColumn)theTableColumn row:(int)theRow - (CPView)tableView:(CPTableView)theTableView dataViewForTableColumn:(CPTableColumn)theTableColumn row:(int)theRow
{ {
var dataView = nil; var dataView = nil;
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_)) if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_))
dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView
dataViewForTableColumn:theTableColumn dataViewForTableColumn:theTableColumn
item:[_outlineView itemAtRow:theRow]]; item:[_outlineView itemAtRow:theRow]];
if (!dataView) if (!dataView)
dataView = [theTableColumn dataViewForRow:theRow]; dataView = [theTableColumn dataViewForRow:theRow];
return dataView; return dataView;
} }
@@ -1003,10 +1168,18 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
{ {
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_)) if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_))
return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldSelectItem:[_outlineView itemAtRow:theRow]]; return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldSelectItem:[_outlineView itemAtRow:theRow]];
return YES; 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 - (float)tableView:(CPTableView)theTableView heightOfRow:(int)theRow
{ {
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_heightOfRowByItem_)) 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_)) 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; return NO;
} }
@@ -1080,9 +1253,82 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
CGContextAddLineToPoint(context, 0.0, 0.0); CGContextAddLineToPoint(context, 0.0, 0.0);
CGContextClosePath(context); CGContextClosePath(context);
CGContextSetFillColor(context,
CGContextSetFillColor(context, [self isHighlighted] ? [CPColor whiteColor] : [CPColor grayColor]); colorForDisclosureTriangle([self hasThemeState:CPThemeStateSelected],
[self hasThemeState:CPThemeStateHighlighted]));
CGContextFillPath(context); 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 @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/CPDictionary.j>
@import <Foundation/CPPropertyListSerialization.j> @import <Foundation/CPPropertyListSerialization.j>
#include "Platform/Platform.h"
CPGeneralPboard = @"CPGeneralPboard"; CPGeneralPboard = @"CPGeneralPboard";
CPFontPboard = @"CPFontPboard"; CPFontPboard = @"CPFontPboard";
+65 -41
View File
@@ -25,14 +25,12 @@
@import "CPMenu.j" @import "CPMenu.j"
@import "CPMenuItem.j" @import "CPMenuItem.j"
#include "CoreGraphics/CGGeometry.h"
var VISIBLE_MARGIN = 7.0; var VISIBLE_MARGIN = 7.0;
CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
/*! /*!
@ingroup appkit @ingroup appkit
@class CPPopUpButton @class CPPopUpButton
@@ -42,11 +40,11 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{ {
int _selectedIndex; int _selectedIndex;
CPRectEdge _preferredEdge; CPRectEdge _preferredEdge;
CPMenu _menu; CPMenu _menu;
} }
+ (CPString)themeClass + (CPString)defaultThemeClass
{ {
return "popup-button"; return "popup-button";
} }
@@ -60,21 +58,21 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
- (id)initWithFrame:(CGRect)aFrame pullsDown:(BOOL)shouldPullDown - (id)initWithFrame:(CGRect)aFrame pullsDown:(BOOL)shouldPullDown
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
_selectedIndex = CPNotFound; _selectedIndex = CPNotFound;
_preferredEdge = CPMaxYEdge; _preferredEdge = CPMaxYEdge;
[self setValue:CPImageLeft forThemeAttribute:@"image-position"]; [self setValue:CPImageLeft forThemeAttribute:@"image-position"];
[self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"]; [self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"];
[self setValue:CPLineBreakByTruncatingTail forThemeAttribute:@"line-break-mode"]; [self setValue:CPLineBreakByTruncatingTail forThemeAttribute:@"line-break-mode"];
[self setMenu:[[CPMenu alloc] initWithTitle:@""]]; [self setMenu:[[CPMenu alloc] initWithTitle:@""]];
[self setPullsDown:shouldPullDown]; [self setPullsDown:shouldPullDown];
} }
return self; return self;
} }
@@ -145,7 +143,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{ {
var index = 0, var index = 0,
count = [titles count]; count = [titles count];
for (; index < count; ++index) for (; index < count; ++index)
[self addItemWithTitle:titles[index]]; [self addItemWithTitle:titles[index]];
} }
@@ -159,11 +157,11 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{ {
var items = [self itemArray], var items = [self itemArray],
count = [items count]; count = [items count];
while (count--) while (count--)
if ([items[count] title] == aTitle) if ([items[count] title] == aTitle)
[self removeItemAtIndex:count]; [self removeItemAtIndex:count];
[_menu insertItemWithTitle:aTitle action:NULL keyEquivalent:nil atIndex:anIndex]; [_menu insertItemWithTitle:aTitle action:NULL keyEquivalent:nil atIndex:anIndex];
} }
@@ -173,7 +171,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
- (void)removeAllItems - (void)removeAllItems
{ {
var count = [_menu numberOfItems]; var count = [_menu numberOfItems];
while (count--) while (count--)
[_menu removeItemAtIndex:0]; [_menu removeItemAtIndex:0];
} }
@@ -206,7 +204,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{ {
if (_selectedIndex < 0 || _selectedIndex > [self numberOfItems] - 1) if (_selectedIndex < 0 || _selectedIndex > [self numberOfItems] - 1)
return nil; return nil;
return [_menu itemAtIndex:_selectedIndex]; return [_menu itemAtIndex:_selectedIndex];
} }
@@ -253,15 +251,15 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{ {
if (_selectedIndex == anIndex) if (_selectedIndex == anIndex)
return; return;
if (_selectedIndex >= 0 && ![self pullsDown]) if (_selectedIndex >= 0 && ![self pullsDown])
[[self selectedItem] setState:CPOffState]; [[self selectedItem] setState:CPOffState];
_selectedIndex = anIndex; _selectedIndex = anIndex;
if (_selectedIndex >= 0 && ![self pullsDown]) if (_selectedIndex >= 0 && ![self pullsDown])
[[self selectedItem] setState:CPOnState]; [[self selectedItem] setState:CPOnState];
[self synchronizeTitleAndSelectedItem]; [self synchronizeTitleAndSelectedItem];
} }
@@ -310,7 +308,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
return; return;
var defaultCenter = [CPNotificationCenter defaultCenter]; var defaultCenter = [CPNotificationCenter defaultCenter];
if (_menu) if (_menu)
{ {
[defaultCenter [defaultCenter
@@ -330,7 +328,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
} }
_menu = aMenu; _menu = aMenu;
if (_menu) if (_menu)
{ {
[defaultCenter [defaultCenter
@@ -338,20 +336,20 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
selector:@selector(menuDidAddItem:) selector:@selector(menuDidAddItem:)
name:CPMenuDidAddItemNotification name:CPMenuDidAddItemNotification
object:_menu]; object:_menu];
[defaultCenter [defaultCenter
addObserver:self addObserver:self
selector:@selector(menuDidChangeItem:) selector:@selector(menuDidChangeItem:)
name:CPMenuDidChangeItemNotification name:CPMenuDidChangeItemNotification
object:_menu]; object:_menu];
[defaultCenter [defaultCenter
addObserver:self addObserver:self
selector:@selector(menuDidRemoveItem:) selector:@selector(menuDidRemoveItem:)
name:CPMenuDidRemoveItemNotification name:CPMenuDidRemoveItemNotification
object:_menu]; object:_menu];
} }
[self synchronizeTitleAndSelectedItem]; [self synchronizeTitleAndSelectedItem];
} }
@@ -396,12 +394,13 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{ {
var titles = [], var titles = [],
items = [self itemArray], items = [self itemArray],
index = 0, index = 0,
count = [items count]; count = [items count];
for (; index < count; ++index) 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 else
{ {
var index = [self indexOfItemWithTitle:aTitle]; var index = [self indexOfItemWithTitle:aTitle];
if (index < 0) if (index < 0)
{ {
[self addItemWithTitle:aTitle]; [self addItemWithTitle:aTitle];
index = [self numberOfItems] - 1; index = [self numberOfItems] - 1;
} }
[self selectItemAtIndex:index]; [self selectItemAtIndex:index];
} }
} }
@@ -554,7 +553,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if ([self pullsDown]) if ([self pullsDown])
{ {
var items = [_menu itemArray]; var items = [_menu itemArray];
if ([items count] > 0) if ([items count] > 0)
item = items[0]; item = items[0];
} }
@@ -573,22 +572,22 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
- (void)menuDidAddItem:(CPNotification)aNotification - (void)menuDidAddItem:(CPNotification)aNotification
{ {
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"]; var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"];
if (_selectedIndex < 0) if (_selectedIndex < 0)
[self selectItemAtIndex:0]; [self selectItemAtIndex:0];
else if (index == _selectedIndex) else if (index == _selectedIndex)
[self synchronizeTitleAndSelectedItem]; [self synchronizeTitleAndSelectedItem];
else if (index < _selectedIndex) else if (index < _selectedIndex)
++_selectedIndex; ++_selectedIndex;
if (index == 0 && [self pullsDown]) if (index == 0 && [self pullsDown])
{ {
var items = [_menu itemArray]; var items = [_menu itemArray];
[items[0] setHidden:YES]; [items[0] setHidden:YES];
if (items.length > 0) if (items.length > 0)
[items[1] setHidden:NO]; [items[1] setHidden:NO];
} }
@@ -613,10 +612,10 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if ([self pullsDown] && index != 0) if ([self pullsDown] && index != 0)
return; return;
if (![self pullsDown] && index != _selectedIndex) if (![self pullsDown] && index != _selectedIndex)
return; return;
[self synchronizeTitleAndSelectedItem]; [self synchronizeTitleAndSelectedItem];
} }
@@ -627,7 +626,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
- (void)menuDidRemoveItem:(CPNotification)aNotification - (void)menuDidRemoveItem:(CPNotification)aNotification
{ {
var numberOfItems = [self numberOfItems]; var numberOfItems = [self numberOfItems];
if (numberOfItems <= _selectedIndex && numberOfItems > 0) if (numberOfItems <= _selectedIndex && numberOfItems > 0)
[self selectItemAtIndex:numberOfItems - 1]; [self selectItemAtIndex:numberOfItems - 1];
else else
@@ -661,6 +660,9 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0); location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0);
minimumWidth += standardLeftMargin; minimumWidth += standardLeftMargin;
// To ensure the selected item is highlighted correctly, unset the highlighted item
[menu _highlightItemAtIndex:CPNotFound];
} }
[menu setMinimumWidth:minimumWidth]; [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 - (void)_popUpItemAction:(id)aSender
{ {
[self sendAction:[self action] to:[self target]]; [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 @end
var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey", var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
@@ -720,7 +744,7 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super initWithCoder:aCoder]; self = [super initWithCoder:aCoder];
if (self) if (self)
{ {
// Nothing is currently selected // Nothing is currently selected
@@ -729,7 +753,7 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
[self setMenu:[aCoder decodeObjectForKey:CPPopUpButtonMenuKey]]; [self setMenu:[aCoder decodeObjectForKey:CPPopUpButtonMenuKey]];
[self selectItemAtIndex:[aCoder decodeObjectForKey:CPPopUpButtonSelectedIndexKey]]; [self selectItemAtIndex:[aCoder decodeObjectForKey:CPPopUpButtonSelectedIndexKey]];
} }
return self; return self;
} }
@@ -741,7 +765,7 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeObject:_menu forKey:CPPopUpButtonMenuKey]; [aCoder encodeObject:_menu forKey:CPPopUpButtonMenuKey];
[aCoder encodeInt:_selectedIndex forKey:CPPopUpButtonSelectedIndexKey]; [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 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import <AppKit/CGGeometry.j> @import "CGGeometry.j"
@import <AppKit/CPImageView.j> @import "CPImageView.j"
@import <AppKit/CPView.j> @import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
/* /*
+19 -15
View File
@@ -25,28 +25,29 @@
@import "CPButton.j" @import "CPButton.j"
/*! /*!
@ingroup appkit @ingroup appkit
from this mailing list thread: 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: Creating a checkbox is easy enough:
checkbox = [[CPCheckBox alloc] initWithFrame:aFrame]; checkbox = [[CPCheckBox alloc] initWithFrame:aFrame];
That's basically all there is to it. Radio buttons are very similar, That's basically all there is to it. Radio buttons are very similar,
the key difference is the introduction of a new class CPRadioGroup, the key difference is the introduction of a new class CPRadioGroup,
which defines which radio buttons are part of the same group: which defines which radio buttons are part of the same group:
[myRadioButton setRadioGroup:aRadioGroup]; [myRadioButton setRadioGroup:aRadioGroup];
Every radio button receives a unique radio group by default (so if you Every radio button receives a unique radio group by default (so if you
do nothing further, they will all behave independently), but you can do nothing further, they will all behave independently), but you can
use an existing radio button's group with other buttons as so: use an existing radio button's group with other buttons as so:
button1 = [[CPRadio alloc] initWithFrame:aFrame]; button1 = [[CPRadio alloc] initWithFrame:aFrame];
... ...
button2 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1 button2 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1
@@ -55,13 +56,16 @@
button3 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1 button3 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1
radioGroup]]; radioGroup]];
...etc... ...etc...
Here, all the radio buttons will act "together". [[button1 radioGroup] Here, all the radio buttons will act "together". [[button1 radioGroup]
allRadios] returns every button that's part of this group, and allRadios] returns every button that's part of this group, and
[[button1 radioGroup] selectedRadio] returns the currently selected [[button1 radioGroup] selectedRadio] returns the currently selected
option. option.
*/ */
CPRadioImageOffset = 4.0;
@implementation CPRadio : CPButton @implementation CPRadio : CPButton
{ {
CPRadioGroup _radioGroup; CPRadioGroup _radioGroup;
@@ -86,7 +90,7 @@
return button; return button;
} }
+ (CPString)themeClass + (CPString)defaultThemeClass
{ {
return @"radio"; return @"radio";
} }
@@ -95,7 +99,7 @@
- (id)initWithFrame:(CGRect)aFrame radioGroup:(CPRadioGroup)aRadioGroup - (id)initWithFrame:(CGRect)aFrame radioGroup:(CPRadioGroup)aRadioGroup
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
[self setRadioGroup:aRadioGroup]; [self setRadioGroup:aRadioGroup];
@@ -109,8 +113,8 @@
[self setBordered:YES]; [self setBordered:YES];
} }
return self; return self;
} }
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
@@ -141,7 +145,7 @@
- (void)setObjectValue:(id)aValue - (void)setObjectValue:(id)aValue
{ {
[super setObjectValue:aValue]; [super setObjectValue:aValue];
if ([self state] === CPOnState) if ([self state] === CPOnState)
[_radioGroup _setSelectedRadio:self]; [_radioGroup _setSelectedRadio:self];
} }
+47 -53
View File
@@ -23,22 +23,23 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
CPDeleteKeyCode = 8; CPDeleteKeyCode = 8;
CPTabKeyCode = 9; CPTabKeyCode = 9;
CPReturnKeyCode = 13; CPReturnKeyCode = 13;
CPEscapeKeyCode = 27; CPEscapeKeyCode = 27;
CPSpaceKeyCode = 32; CPSpaceKeyCode = 32;
CPPageUpKeyCode = 33; CPPageUpKeyCode = 33;
CPPageDownKeyCode = 34; CPPageDownKeyCode = 34;
CPLeftArrowKeyCode = 37; CPLeftArrowKeyCode = 37;
CPUpArrowKeyCode = 38; CPUpArrowKeyCode = 38;
CPRightArrowKeyCode = 39; CPRightArrowKeyCode = 39;
CPDownArrowKeyCode = 40; CPDownArrowKeyCode = 40;
CPDeleteForwardKeyCode = 46;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPResponder @class CPResponder
Subclasses of CPResonder can be part of the responder chain. Subclasses of CPResonder can be part of the responder chain.
*/ */
@implementation CPResponder : CPObject @implementation CPResponder : CPObject
@@ -104,42 +105,24 @@ CPDownArrowKeyCode = 40;
for (; index < count; ++index) 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:)]; for (var s = 0, scount = selectorNames.length; s < scount; s++)
break; {
case CPPageDownKeyCode: [self doCommandBySelector:@selector(pageDown:)]; var selector = selectorNames[s];
break; if (!selector)
case CPLeftArrowKeyCode: [self doCommandBySelector:@selector(moveLeft:)]; continue;
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;
case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask; [self doCommandBySelector:CPSelectorFromString(selector)];
}
if (!shift)
[self doCommandBySelector:@selector(insertTab:)];
else
[self doCommandBySelector:@selector(insertBackTab:)];
break;
default: [self insertText:[event characters]];
} }
else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)) && [self respondsToSelector:@selector(insertText:)])
[self insertText:[event characters]];
} }
} }
@@ -239,6 +222,15 @@ CPDownArrowKeyCode = 40;
[_nextResponder performSelector:_cmd withObject:anEvent]; [_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. FIXME This description is bad.
Based on \c anEvent, the receiver should simulate the event. Based on \c anEvent, the receiver should simulate the event.
@@ -269,10 +261,6 @@ CPDownArrowKeyCode = 40;
[[self nextResponder] insertNewline:aSender]; [[self nextResponder] insertNewline:aSender];
} }
- (void)cancel:(id)sender
{
}
- (void)insertTab:(id)sender - (void)insertTab:(id)sender
{ {
} }
@@ -312,10 +300,10 @@ CPDownArrowKeyCode = 40;
*/ */
- (BOOL)tryToPerform:(SEL)aSelector with:(id)anObject - (BOOL)tryToPerform:(SEL)aSelector with:(id)anObject
{ {
if([self respondsToSelector:aSelector]) if ([self respondsToSelector:aSelector])
{ {
[self performSelector:aSelector withObject:anObject]; [self performSelector:aSelector withObject:anObject];
return YES; return YES;
} }
@@ -354,7 +342,8 @@ CPDownArrowKeyCode = 40;
@end @end
var CPResponderNextResponderKey = @"CPResponderNextResponderKey"; var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
CPResponderMenuKey = @"CPResponderMenuKey";
@implementation CPResponder (CPCoding) @implementation CPResponder (CPCoding)
@@ -366,10 +355,13 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super init]; self = [super init];
if (self) if (self)
{
_nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey]; _nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey];
_menu = [aCoder decodeObjectForKey:CPResponderMenuKey];
}
return self; return self;
} }
@@ -382,6 +374,8 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
// This will come out nil on the other side with decodeObjectForKey: // This will come out nil on the other side with decodeObjectForKey:
if (_nextResponder !== nil) if (_nextResponder !== nil)
[aCoder encodeConditionalObject:_nextResponder forKey:CPResponderNextResponderKey]; [aCoder encodeConditionalObject:_nextResponder forKey:CPResponderNextResponderKey];
[aCoder encodeObject:_menu forKey:CPResponderMenuKey];
} }
@end @end
+1 -1
View File
@@ -1,5 +1,5 @@
@import <AppKit/CPPanel.j> @import "CPPanel.j"
@implementation CPSavePanel : CPPanel @implementation CPSavePanel : CPPanel
-2
View File
@@ -1,8 +1,6 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
#import "CoreGraphics/CGGeometry.h"
#import "Platform/Platform.h"
@implementation CPScreen : CPObject @implementation CPScreen : CPObject
{ {
+386 -96
View File
@@ -20,14 +20,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CPView.j" @import "CPBox.j"
@import "CPClipView.j" @import "CPClipView.j"
@import "CPScroller.j" @import "CPScroller.j"
@import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
/*! /*!
@ingroup appkit @ingroup appkit
@class CPScrollView @class CPScrollView
@@ -37,23 +36,39 @@
*/ */
@implementation CPScrollView : CPView @implementation CPScrollView : CPView
{ {
CPClipView _contentView; CPClipView _contentView;
CPClipView _headerClipView; CPClipView _headerClipView;
CPView _cornerView; CPView _cornerView;
CPView _bottomCornerView;
BOOL _hasVerticalScroller; BOOL _hasVerticalScroller;
BOOL _hasHorizontalScroller; BOOL _hasHorizontalScroller;
BOOL _autohidesScrollers; BOOL _autohidesScrollers;
CPScroller _verticalScroller; CPScroller _verticalScroller;
CPScroller _horizontalScroller; CPScroller _horizontalScroller;
int _recursionCount; int _recursionCount;
float _verticalLineScroll; float _verticalLineScroll;
float _verticalPageScroll; float _verticalPageScroll;
float _horizontalLineScroll; float _horizontalLineScroll;
float _horizontalPageScroll; 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 - (id)initWithFrame:(CGRect)aFrame
@@ -68,14 +83,18 @@
_horizontalLineScroll = 10.0; _horizontalLineScroll = 10.0;
_horizontalPageScroll = 10.0; _horizontalPageScroll = 10.0;
_contentView = [[CPClipView alloc] initWithFrame:[self bounds]]; _borderType = CPNoBorder;
_contentView = [[CPClipView alloc] initWithFrame:[self _insetBounds]];
[self addSubview:_contentView]; [self addSubview:_contentView];
_headerClipView = [[CPClipView alloc] init]; _headerClipView = [[CPClipView alloc] init];
[self addSubview:_headerClipView]; [self addSubview:_headerClipView];
_bottomCornerView = [[CPView alloc] init];
[self addSubview:_bottomCornerView];
[self setHasVerticalScroller:YES]; [self setHasVerticalScroller:YES];
[self setHasHorizontalScroller:YES]; [self setHasHorizontalScroller:YES];
} }
@@ -83,11 +102,70 @@
return self; 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 // Determining component sizes
/*! /*!
Returns the size of the scroll view's content view. Returns the size of the scroll view's content view.
*/ */
- (CGRect)contentSize - (CGSize)contentSize
{ {
return [_contentView frame].size; return [_contentView frame].size;
} }
@@ -106,7 +184,7 @@
*/ */
- (void)setContentView:(CPClipView)aContentView - (void)setContentView:(CPClipView)aContentView
{ {
if (_contentView !== aContentView || !aContentView) if (_contentView === aContentView || !aContentView)
return; return;
var documentView = [aContentView documentView]; var documentView = [aContentView documentView];
@@ -153,16 +231,16 @@
*/ */
- (void)reflectScrolledClipView:(CPClipView)aClipView - (void)reflectScrolledClipView:(CPClipView)aClipView
{ {
if(_contentView !== aClipView) if (_contentView !== aClipView)
return; return;
if (_recursionCount > 5) if (_recursionCount > 5)
return; return;
++_recursionCount; ++_recursionCount;
var documentView = [self documentView]; var documentView = [self documentView];
if (!documentView) if (!documentView)
{ {
if (_autohidesScrollers) if (_autohidesScrollers)
@@ -176,7 +254,7 @@
// [_horizontalScroller setEnabled:NO]; // [_horizontalScroller setEnabled:NO];
} }
[_contentView setFrame:[self bounds]]; [_contentView setFrame:[self _insetBounds]];
[_headerClipView setFrame:_CGRectMakeZero()]; [_headerClipView setFrame:_CGRectMakeZero()];
--_recursionCount; --_recursionCount;
@@ -185,7 +263,7 @@
} }
var documentFrame = [documentView frame], // the size of the whole document 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], headerClipViewFrame = [self _headerClipViewFrame],
headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame); headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame);
@@ -235,11 +313,10 @@
if (shouldShowVerticalScroller) if (shouldShowVerticalScroller)
{ {
var verticalScrollerY = MAX(_CGRectGetHeight([self _cornerViewFrame]), headerClipViewHeight), var verticalScrollerY =
verticalScrollerHeight = _CGRectGetHeight([self bounds]) - verticalScrollerY; MAX(_CGRectGetMinY(contentFrame), MAX(_CGRectGetMaxY([self _cornerViewFrame]), _CGRectGetMaxY(headerClipViewFrame)));
if (shouldShowHorizontalScroller) var verticalScrollerHeight = _CGRectGetMaxY(contentFrame) - verticalScrollerY;
verticalScrollerHeight -= horizontalScrollerHeight;
[_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height]; [_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
[_verticalScroller setKnobProportion:_CGRectGetHeight(contentFrame) / _CGRectGetHeight(documentFrame)]; [_verticalScroller setKnobProportion:_CGRectGetHeight(contentFrame) / _CGRectGetHeight(documentFrame)];
@@ -250,12 +327,12 @@
[_verticalScroller setFloatValue:0.0]; [_verticalScroller setFloatValue:0.0];
[_verticalScroller setKnobProportion:1.0]; [_verticalScroller setKnobProportion:1.0];
} }
if (shouldShowHorizontalScroller) if (shouldShowHorizontalScroller)
{ {
[_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width]; [_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
[_horizontalScroller setKnobProportion:_CGRectGetWidth(contentFrame) / _CGRectGetWidth(documentFrame)]; [_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) else if (wasShowingHorizontalScroller)
{ {
@@ -267,9 +344,36 @@
[_headerClipView setFrame:headerClipViewFrame]; [_headerClipView setFrame:headerClipViewFrame];
[_cornerView setFrame:[self _cornerViewFrame]]; [_cornerView setFrame:[self _cornerViewFrame]];
[[self bottomCornerView] setFrame:[self _bottomCornerViewFrame]];
[[self bottomCornerView] setBackgroundColor:[self currentValueForThemeAttribute:@"bottom-corner-color"]];
--_recursionCount; --_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 // Managing Scrollers
/*! /*!
Sets the scroll view's horizontal scroller. Sets the scroll view's horizontal scroller.
@@ -279,13 +383,13 @@
{ {
if (_horizontalScroller === aScroller) if (_horizontalScroller === aScroller)
return; return;
[_horizontalScroller removeFromSuperview]; [_horizontalScroller removeFromSuperview];
[_horizontalScroller setTarget:nil]; [_horizontalScroller setTarget:nil];
[_horizontalScroller setAction:nil]; [_horizontalScroller setAction:nil];
_horizontalScroller = aScroller; _horizontalScroller = aScroller;
[_horizontalScroller setTarget:self]; [_horizontalScroller setTarget:self];
[_horizontalScroller setAction:@selector(_horizontalScrollerDidScroll:)]; [_horizontalScroller setAction:@selector(_horizontalScrollerDidScroll:)];
@@ -316,8 +420,10 @@
if (_hasHorizontalScroller && !_horizontalScroller) if (_hasHorizontalScroller && !_horizontalScroller)
{ {
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth]+1), [CPScroller scrollerWidth])]]; var bounds = [self _insetBounds];
[[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth])];
[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]; [self reflectScrolledClipView:_contentView];
@@ -339,13 +445,13 @@
{ {
if (_verticalScroller === aScroller) if (_verticalScroller === aScroller)
return; return;
[_verticalScroller removeFromSuperview]; [_verticalScroller removeFromSuperview];
[_verticalScroller setTarget:nil]; [_verticalScroller setTarget:nil];
[_verticalScroller setAction:nil]; [_verticalScroller setAction:nil];
_verticalScroller = aScroller; _verticalScroller = aScroller;
[_verticalScroller setTarget:self]; [_verticalScroller setTarget:self];
[_verticalScroller setAction:@selector(_verticalScrollerDidScroll:)]; [_verticalScroller setAction:@selector(_verticalScrollerDidScroll:)];
@@ -377,8 +483,10 @@
if (_hasVerticalScroller && !_verticalScroller) if (_hasVerticalScroller && !_verticalScroller)
{ {
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight([self bounds]), [CPScroller scrollerWidth]+1))]]; var bounds = [self _insetBounds];
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight([self bounds]))];
[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]; [self reflectScrolledClipView:_contentView];
@@ -403,7 +511,7 @@
return; return;
_autohidesScrollers = autohidesScrollers; _autohidesScrollers = autohidesScrollers;
[self reflectScrolledClipView:_contentView]; [self reflectScrolledClipView:_contentView];
} }
@@ -445,9 +553,7 @@
- (CPView)_headerView - (CPView)_headerView
{ {
var headerClipViewSubviews = [_headerClipView subviews]; return [_headerClipView documentView];
return [headerClipViewSubviews count] ? headerClipViewSubviews[0] : nil;
} }
- (CGRect)_cornerViewFrame - (CGRect)_cornerViewFrame
@@ -455,11 +561,11 @@
if (!_cornerView) if (!_cornerView)
return _CGRectMakeZero(); return _CGRectMakeZero();
var bounds = [self bounds], var bounds = [self _insetBounds],
frame = [_cornerView frame]; frame = [_cornerView frame];
frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame); frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame);
frame.origin.y = 0; frame.origin.y = _CGRectGetMinY(bounds);
return frame; return frame;
} }
@@ -471,7 +577,7 @@
if (!headerView) if (!headerView)
return _CGRectMakeZero(); return _CGRectMakeZero();
var frame = [self bounds]; var frame = [self _insetBounds];
frame.size.height = _CGRectGetHeight([headerView frame]); frame.size.height = _CGRectGetHeight([headerView frame]);
frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]); frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]);
@@ -479,33 +585,69 @@
return frame; 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 */ /* @ignore */
- (void)_verticalScrollerDidScroll:(CPScroller)aScroller - (void)_verticalScrollerDidScroll:(CPScroller)aScroller
{ {
var value = [aScroller floatValue], var value = [aScroller floatValue],
documentFrame = [[_contentView documentView] frame]; documentFrame = [[_contentView documentView] frame],
contentBounds = [_contentView bounds]; contentBounds = [_contentView bounds];
switch ([_verticalScroller hitPart]) switch ([_verticalScroller hitPart])
{ {
case CPScrollerDecrementLine: contentBounds.origin.y -= _verticalLineScroll; case CPScrollerDecrementLine: contentBounds.origin.y -= _verticalLineScroll;
break; break;
case CPScrollerIncrementLine: contentBounds.origin.y += _verticalLineScroll; case CPScrollerIncrementLine: contentBounds.origin.y += _verticalLineScroll;
break; break;
case CPScrollerDecrementPage: contentBounds.origin.y -= _CGRectGetHeight(contentBounds) - _verticalPageScroll; case CPScrollerDecrementPage: contentBounds.origin.y -= _CGRectGetHeight(contentBounds) - _verticalPageScroll;
break; break;
case CPScrollerIncrementPage: contentBounds.origin.y += _CGRectGetHeight(contentBounds) - _verticalPageScroll; case CPScrollerIncrementPage: contentBounds.origin.y += _CGRectGetHeight(contentBounds) - _verticalPageScroll;
break; break;
case CPScrollerKnobSlot: case CPScrollerKnobSlot:
case CPScrollerKnob: case CPScrollerKnob:
// We want integral bounds! // We want integral bounds!
default: contentBounds.origin.y = ROUND(value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds))); default: contentBounds.origin.y = ROUND(value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds)));
} }
[_contentView scrollToPoint:contentBounds.origin]; [_contentView scrollToPoint:contentBounds.origin];
} }
@@ -515,21 +657,21 @@
var value = [aScroller floatValue], var value = [aScroller floatValue],
documentFrame = [[self documentView] frame], documentFrame = [[self documentView] frame],
contentBounds = [_contentView bounds]; contentBounds = [_contentView bounds];
switch ([_horizontalScroller hitPart]) switch ([_horizontalScroller hitPart])
{ {
case CPScrollerDecrementLine: contentBounds.origin.x -= _horizontalLineScroll; case CPScrollerDecrementLine: contentBounds.origin.x -= _horizontalLineScroll;
break; break;
case CPScrollerIncrementLine: contentBounds.origin.x += _horizontalLineScroll; case CPScrollerIncrementLine: contentBounds.origin.x += _horizontalLineScroll;
break; break;
case CPScrollerDecrementPage: contentBounds.origin.x -= _CGRectGetWidth(contentBounds) - _horizontalPageScroll; case CPScrollerDecrementPage: contentBounds.origin.x -= _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
break; break;
case CPScrollerIncrementPage: contentBounds.origin.x += _CGRectGetWidth(contentBounds) - _horizontalPageScroll; case CPScrollerIncrementPage: contentBounds.origin.x += _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
break; break;
case CPScrollerKnobSlot: case CPScrollerKnobSlot:
case CPScrollerKnob: case CPScrollerKnob:
// We want integral bounds! // We want integral bounds!
@@ -554,7 +696,7 @@
/* /*
@ignore @ignore
*/ */
-(void)resizeSubviewsWithOldSize:(CGSize)aSize - (void)resizeSubviewsWithOldSize:(CGSize)aSize
{ {
[self reflectScrolledClipView:_contentView]; [self reflectScrolledClipView:_contentView];
} }
@@ -664,35 +806,169 @@
return _verticalPageScroll; 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. Handles a scroll wheel event from the user.
@param anEvent the scroll wheel event @param anEvent the scroll wheel event
*/ */
- (void)scrollWheel:(CPEvent)anEvent - (void)scrollWheel:(CPEvent)anEvent
{ {
var documentFrame = [[self documentView] frame], [self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] deltaY:[anEvent deltaY]];
contentBounds = [_contentView bounds]; }
- (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! // We want integral bounds!
contentBounds.origin.x = ROUND(contentBounds.origin.x + [anEvent deltaX] * _horizontalLineScroll); contentBounds.origin.x = ROUND(contentBounds.origin.x + deltaX);
contentBounds.origin.y = ROUND(contentBounds.origin.y + [anEvent deltaY] * _verticalLineScroll); contentBounds.origin.y = ROUND(contentBounds.origin.y + deltaY);
[_contentView scrollToPoint:contentBounds.origin]; var constrainedOrigin = [_contentView constrainScrollPoint:CGPointCreateCopy(contentBounds.origin)],
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)]; 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 - (void)scrollPageUp:(id)sender
{
[self interpretKeyEvents:[anEvent]];
}
- (void)pageUp:(id)sender
{ {
var contentBounds = [_contentView bounds]; var contentBounds = [_contentView bounds];
[self moveByOffset:CGSizeMake(0.0, -(_CGRectGetHeight(contentBounds) - _verticalPageScroll))]; [self moveByOffset:CGSizeMake(0.0, -(_CGRectGetHeight(contentBounds) - _verticalPageScroll))];
} }
- (void)pageDown:(id)sender - (void)scrollPageDown:(id)sender
{ {
var contentBounds = [_contentView bounds]; var contentBounds = [_contentView bounds];
[self moveByOffset:CGSizeMake(0.0, _CGRectGetHeight(contentBounds) - _verticalPageScroll)]; [self moveByOffset:CGSizeMake(0.0, _CGRectGetHeight(contentBounds) - _verticalPageScroll)];
@@ -732,18 +1008,20 @@
@end @end
var CPScrollViewContentViewKey = "CPScrollViewContentView", var CPScrollViewContentViewKey = @"CPScrollViewContentView",
CPScrollViewHeaderClipViewKey = "CPScrollViewHeaderClipViewKey", CPScrollViewHeaderClipViewKey = @"CPScrollViewHeaderClipViewKey",
CPScrollViewVLineScrollKey = "CPScrollViewVLineScroll", CPScrollViewVLineScrollKey = @"CPScrollViewVLineScroll",
CPScrollViewHLineScrollKey = "CPScrollViewHLineScroll", CPScrollViewHLineScrollKey = @"CPScrollViewHLineScroll",
CPScrollViewVPageScrollKey = "CPScrollViewVPageScroll", CPScrollViewVPageScrollKey = @"CPScrollViewVPageScroll",
CPScrollViewHPageScrollKey = "CPScrollViewHPageScroll", CPScrollViewHPageScrollKey = @"CPScrollViewHPageScroll",
CPScrollViewHasVScrollerKey = "CPScrollViewHasVScroller", CPScrollViewHasVScrollerKey = @"CPScrollViewHasVScroller",
CPScrollViewHasHScrollerKey = "CPScrollViewHasHScroller", CPScrollViewHasHScrollerKey = @"CPScrollViewHasHScroller",
CPScrollViewVScrollerKey = "CPScrollViewVScroller", CPScrollViewVScrollerKey = @"CPScrollViewVScroller",
CPScrollViewHScrollerKey = "CPScrollViewHScroller", CPScrollViewHScrollerKey = @"CPScrollViewHScroller",
CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller", CPScrollViewAutohidesScrollerKey = @"CPScrollViewAutohidesScroller",
CPScrollViewCornerViewKey = "CPScrollViewCornerViewKey"; CPScrollViewCornerViewKey = @"CPScrollViewCornerViewKey",
CPScrollViewBottomCornerViewKey = @"CPScrollViewBottomCornerViewKey",
CPScrollViewBorderTypeKey = @"CPScrollViewBorderTypeKey";
@implementation CPScrollView (CPCoding) @implementation CPScrollView (CPCoding)
@@ -756,10 +1034,16 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
_horizontalLineScroll = [aCoder decodeFloatForKey:CPScrollViewHLineScrollKey]; _horizontalLineScroll = [aCoder decodeFloatForKey:CPScrollViewHLineScrollKey];
_horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey]; _horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
_contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey]; _contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
_headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey]; _headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey];
if (!_headerClipView)
{
_headerClipView = [[CPClipView alloc] init];
[self addSubview:_headerClipView];
}
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey]; _verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey]; _horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
@@ -767,35 +1051,41 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
_hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey]; _hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
_autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey]; _autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
_borderType = [aCoder decodeIntForKey:CPScrollViewBorderTypeKey];
_cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey]; _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. // 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]]; [[CPRunLoop currentRunLoop] performSelector:@selector(reflectScrolledClipView:) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
} }
return self; return self;
} }
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey]; [aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey];
[aCoder encodeObject:_headerClipView forKey:CPScrollViewHeaderClipViewKey]; [aCoder encodeObject:_headerClipView forKey:CPScrollViewHeaderClipViewKey];
[aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey]; [aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey];
[aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey]; [aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey];
[aCoder encodeFloat:_verticalLineScroll forKey:CPScrollViewVLineScrollKey]; [aCoder encodeFloat:_verticalLineScroll forKey:CPScrollViewVLineScrollKey];
[aCoder encodeFloat:_verticalPageScroll forKey:CPScrollViewVPageScrollKey]; [aCoder encodeFloat:_verticalPageScroll forKey:CPScrollViewVPageScrollKey];
[aCoder encodeFloat:_horizontalLineScroll forKey:CPScrollViewHLineScrollKey]; [aCoder encodeFloat:_horizontalLineScroll forKey:CPScrollViewHLineScrollKey];
[aCoder encodeFloat:_horizontalPageScroll forKey:CPScrollViewHPageScrollKey]; [aCoder encodeFloat:_horizontalPageScroll forKey:CPScrollViewHPageScrollKey];
[aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey]; [aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey];
[aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey]; [aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey];
[aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey]; [aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey];
[aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey]; [aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey];
[aCoder encodeObject:_bottomCornerView forKey:CPScrollViewBottomCornerViewKey];
[aCoder encodeInt:_borderType forKey:CPScrollViewBorderTypeKey];
} }
@end @end
+93 -81
View File
@@ -22,8 +22,6 @@
@import "CPControl.j" @import "CPControl.j"
#include "CoreGraphics/CGGeometry.h"
// CPScroller Constants // CPScroller Constants
CPScrollerNoPart = 0; CPScrollerNoPart = 0;
@@ -41,9 +39,9 @@ CPNoScrollerParts = 0;
CPOnlyScrollerArrows = 1; CPOnlyScrollerArrows = 1;
CPAllScrollerParts = 2; CPAllScrollerParts = 2;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPScroller @class CPScroller
*/ */
var PARTS_ARRANGEMENT = [CPScrollerKnobSlot, CPScrollerDecrementLine, CPScrollerIncrementLine, CPScrollerKnob], var PARTS_ARRANGEMENT = [CPScrollerKnobSlot, CPScrollerDecrementLine, CPScrollerIncrementLine, CPScrollerKnob],
@@ -72,24 +70,25 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
CGPoint _trackingStartPoint; CGPoint _trackingStartPoint;
} }
+ (CPString)themeClass + (CPString)defaultThemeClass
{ {
return "scroller"; return "scroller";
} }
+ (id)themeAttributes + (id)themeAttributes
{ {
return [CPDictionary dictionaryWithObjects:[ [CPNull null], [CPNull null], [CPNull null], [CPNull null], return [CPDictionary dictionaryWithJSObject:{
_CGSizeMakeZero(), _CGSizeMakeZero(), _CGInsetMakeZero(), _CGInsetMakeZero(), _CGSizeMakeZero()] @"scroller-width": 15.0,
forKeys:[ @"knob-slot-color", @"knob-slot-color": [CPColor lightGrayColor],
@"decrement-line-color", @"decrement-line-color": [CPNull null],
@"increment-line-color", @"increment-line-color": [CPNull null],
@"knob-color", @"knob-color": [CPColor grayColor],
@"decrement-line-size", @"decrement-line-size":_CGSizeMakeZero(),
@"increment-line-size", @"increment-line-size":_CGSizeMakeZero(),
@"track-inset", @"track-inset":_CGInsetMakeZero(),
@"knob-inset", @"knob-inset": _CGInsetMakeZero(),
@"minimum-knob-length"]]; @"minimum-knob-length":21.0
}]
} }
@@ -98,7 +97,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
_controlSize = CPRegularControlSize; _controlSize = CPRegularControlSize;
@@ -106,7 +105,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
[self setFloatValue:0.0]; [self setFloatValue:0.0];
[self setKnobProportion:1.0]; [self setKnobProportion:1.0];
_hitPart = CPScrollerNoPart; _hitPart = CPScrollerNoPart;
[self _calculateIsVertical]; [self _calculateIsVertical];
@@ -121,7 +120,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
*/ */
+ (float)scrollerWidth + (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 + (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 - (id)currentValueForThemeAttribute:(CPString)anAttributeName
{ {
var themeState = _themeState; var themeState = _themeState;
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName) if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
themeState &= ~CPThemeStateHighlighted; themeState &= ~CPThemeStateHighlighted;
return [self valueForThemeAttribute:anAttributeName inState:themeState]; return [self valueForThemeAttribute:anAttributeName inState:themeState];
} }
@@ -205,25 +204,25 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (CPScrollerPart)testPart:(CGPoint)aPoint - (CPScrollerPart)testPart:(CGPoint)aPoint
{ {
aPoint = [self convertPoint:aPoint fromView:nil]; 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. // page rects first since they may overlap with the arrows.
if (CGRectContainsPoint([self rectForPart:CPScrollerKnob], aPoint)) if (CGRectContainsPoint([self rectForPart:CPScrollerKnob], aPoint))
return CPScrollerKnob; return CPScrollerKnob;
if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementPage], aPoint)) if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementPage], aPoint))
return CPScrollerDecrementPage; return CPScrollerDecrementPage;
if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementPage], aPoint)) if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementPage], aPoint))
return CPScrollerIncrementPage; return CPScrollerIncrementPage;
if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementLine], aPoint)) if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementLine], aPoint))
return CPScrollerDecrementLine; return CPScrollerDecrementLine;
if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementLine], aPoint)) if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementLine], aPoint))
return CPScrollerIncrementLine; return CPScrollerIncrementLine;
if (CGRectContainsPoint([self rectForPart:CPScrollerKnobSlot], aPoint)) if (CGRectContainsPoint([self rectForPart:CPScrollerKnobSlot], aPoint))
return CPScrollerKnobSlot; return CPScrollerKnobSlot;
@@ -241,7 +240,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
if (_knobProportion === 1.0) if (_knobProportion === 1.0)
{ {
_usableParts = CPNoScrollerParts; _usableParts = CPNoScrollerParts;
_partRects[CPScrollerDecrementPage] = CGRectMakeZero(); _partRects[CPScrollerDecrementPage] = CGRectMakeZero();
_partRects[CPScrollerKnob] = CGRectMakeZero(); _partRects[CPScrollerKnob] = CGRectMakeZero();
_partRects[CPScrollerIncrementPage] = CGRectMakeZero(); _partRects[CPScrollerIncrementPage] = CGRectMakeZero();
@@ -250,7 +249,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
// In this case, the slot is the entirety of the scroller. // In this case, the slot is the entirety of the scroller.
_partRects[CPScrollerKnobSlot] = CGRectMakeCopy(bounds); _partRects[CPScrollerKnobSlot] = CGRectMakeCopy(bounds);
return; return;
} }
@@ -260,8 +259,8 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
var knobInset = [self currentValueForThemeAttribute:@"knob-inset"], var knobInset = [self currentValueForThemeAttribute:@"knob-inset"],
trackInset = [self currentValueForThemeAttribute:@"track-inset"], trackInset = [self currentValueForThemeAttribute:@"track-inset"],
width = _CGRectGetWidth(bounds), width = _CGRectGetWidth(bounds),
height = _CGRectGetHeight(bounds); height = _CGRectGetHeight(bounds);
if ([self isVertical]) if ([self isVertical])
{ {
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"], var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
@@ -280,11 +279,11 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotHeight); _partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotHeight);
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height); _partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.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(); _partRects[CPScrollerKnob] = _CGRectMakeZero();
if(height < decrementLineSize.height + incrementLineSize.height - 2) if (height < decrementLineSize.height + incrementLineSize.height - 2)
{ {
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero(); _partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero(); _partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
@@ -296,7 +295,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"], var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"], incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"],
effectiveDecrementLineWidth = decrementLineSize.width + trackInset.left, effectiveDecrementLineWidth = decrementLineSize.width + trackInset.left,
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right; effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right,
slotWidth = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth, slotWidth = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"], minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
knobWidth = MAX(minimumKnobLength, (slotWidth * _knobProportion)), knobWidth = MAX(minimumKnobLength, (slotWidth * _knobProportion)),
@@ -309,11 +308,11 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotWidth, height - trackInset.top - trackInset.bottom); _partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotWidth, height - trackInset.top - trackInset.bottom);
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height); _partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.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(); _partRects[CPScrollerKnob] = _CGRectMakeZero();
if(width < decrementLineSize.width + incrementLineSize.width - 2) if (width < decrementLineSize.width + incrementLineSize.width - 2)
{ {
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero(); _partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero(); _partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
@@ -358,9 +357,9 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (CPView)createViewForPart:(CPScrollerPart)aPart - (CPView)createViewForPart:(CPScrollerPart)aPart
{ {
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()]; var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO]; [view setHitTests:NO];
return view; return view;
} }
@@ -374,7 +373,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()]; var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO]; [view setHitTests:NO];
return view; return view;
} }
@@ -388,12 +387,12 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
for (; index < count; ++index) for (; index < count; ++index)
{ {
var part = PARTS_ARRANGEMENT[index]; var part = PARTS_ARRANGEMENT[index];
if (index === 0) if (index === 0)
view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowBelow relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index + 1]]; view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowBelow relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index + 1]];
else else
view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowAbove relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index - 1]]; view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowAbove relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index - 1]];
if (view) if (view)
[view setBackgroundColor:[self currentValueForThemeAttribute:NAMES_FOR_PARTS[part] + "-color"]]; [view setBackgroundColor:[self currentValueForThemeAttribute:NAMES_FOR_PARTS[part] + "-color"]];
} }
@@ -403,7 +402,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
Caches images for the scroll arrow and knob. Caches images for the scroll arrow and knob.
*/ */
- (void)drawParts - (void)drawParts
{ {
[self drawKnobSlot]; [self drawKnobSlot];
[self drawKnob]; [self drawKnob];
[self drawArrow:CPScrollerDecrementArrow highlight:NO]; [self drawArrow:CPScrollerDecrementArrow highlight:NO];
@@ -426,37 +425,37 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (void)trackKnob:(CPEvent)anEvent - (void)trackKnob:(CPEvent)anEvent
{ {
var type = [anEvent type]; var type = [anEvent type];
if (type === CPLeftMouseUp) if (type === CPLeftMouseUp)
{ {
_hitPart = CPScrollerNoPart; _hitPart = CPScrollerNoPart;
return; return;
} }
if (type === CPLeftMouseDown) if (type === CPLeftMouseDown)
{ {
_trackingFloatValue = [self floatValue]; _trackingFloatValue = [self floatValue];
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil]; _trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
} }
else if (type === CPLeftMouseDragged) else if (type === CPLeftMouseDragged)
{ {
var knobRect = [self rectForPart:CPScrollerKnob], var knobRect = [self rectForPart:CPScrollerKnob],
knobSlotRect = [self rectForPart:CPScrollerKnobSlot], knobSlotRect = [self rectForPart:CPScrollerKnobSlot],
remainder = ![self isVertical] ? (_CGRectGetWidth(knobSlotRect) - _CGRectGetWidth(knobRect)) : (_CGRectGetHeight(knobSlotRect) - _CGRectGetHeight(knobRect)); remainder = ![self isVertical] ? (_CGRectGetWidth(knobSlotRect) - _CGRectGetWidth(knobRect)) : (_CGRectGetHeight(knobSlotRect) - _CGRectGetHeight(knobRect));
if (remainder <= 0) if (remainder <= 0)
[self setFloatValue:0.0]; [self setFloatValue:0.0];
else 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; delta = ![self isVertical] ? location.x - _trackingStartPoint.x : location.y - _trackingStartPoint.y;
[self setFloatValue:_trackingFloatValue + delta / remainder]; [self setFloatValue:_trackingFloatValue + delta / remainder];
} }
} }
[CPApp setTarget:self selector:@selector(trackKnob:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES]; [CPApp setTarget:self selector:@selector(trackKnob:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
[self sendAction:[self action] to:[self target]]; [self sendAction:[self action] to:[self target]];
@@ -474,26 +473,26 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
{ {
[self highlight:NO]; [self highlight:NO];
[CPEvent stopPeriodicEvents]; [CPEvent stopPeriodicEvents];
_hitPart = CPScrollerNoPart; _hitPart = CPScrollerNoPart;
return; return;
} }
if (type === CPLeftMouseDown) if (type === CPLeftMouseDown)
{ {
_trackingPart = [self hitPart]; _trackingPart = [self hitPart];
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil]; _trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if ([anEvent modifierFlags] & CPAlternateKeyMask) if ([anEvent modifierFlags] & CPAlternateKeyMask)
{ {
if (_trackingPart == CPScrollerDecrementLine) if (_trackingPart == CPScrollerDecrementLine)
_hitPart = CPScrollerDecrementPage; _hitPart = CPScrollerDecrementPage;
else if (_trackingPart == CPScrollerIncrementLine) else if (_trackingPart == CPScrollerIncrementLine)
_hitPart = CPScrollerIncrementPage; _hitPart = CPScrollerIncrementPage;
else if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage) else if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
{ {
var knobRect = [self rectForPart:CPScrollerKnob], var knobRect = [self rectForPart:CPScrollerKnob],
@@ -502,42 +501,42 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
remainder = (![self isVertical] ? _CGRectGetWidth(knobSlotRect) : _CGRectGetHeight(knobSlotRect)) - knobWidth; remainder = (![self isVertical] ? _CGRectGetWidth(knobSlotRect) : _CGRectGetHeight(knobSlotRect)) - knobWidth;
[self setFloatValue:((![self isVertical] ? _trackingStartPoint.x - _CGRectGetMinX(knobSlotRect) : _trackingStartPoint.y - _CGRectGetMinY(knobSlotRect)) - knobWidth / 2.0) / remainder]; [self setFloatValue:((![self isVertical] ? _trackingStartPoint.x - _CGRectGetMinX(knobSlotRect) : _trackingStartPoint.y - _CGRectGetMinY(knobSlotRect)) - knobWidth / 2.0) / remainder];
_hitPart = CPScrollerKnob; _hitPart = CPScrollerKnob;
[self sendAction:[self action] to:[self target]]; [self sendAction:[self action] to:[self target]];
// Now just track the knob. // Now just track the knob.
return [self trackKnob:anEvent]; return [self trackKnob:anEvent];
} }
} }
[self highlight:YES]; [self highlight:YES];
[self sendAction:[self action] to:[self target]]; [self sendAction:[self action] to:[self target]];
[CPEvent startPeriodicEventsAfterDelay:0.5 withPeriod:0.04]; [CPEvent startPeriodicEventsAfterDelay:0.5 withPeriod:0.04];
} }
else if (type === CPLeftMouseDragged) else if (type === CPLeftMouseDragged)
{ {
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil]; _trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage) if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
{ {
var hitPart = [self testPart:[anEvent locationInWindow]]; var hitPart = [self testPart:[anEvent locationInWindow]];
if (hitPart == CPScrollerDecrementPage || hitPart == CPScrollerIncrementPage) if (hitPart == CPScrollerDecrementPage || hitPart == CPScrollerIncrementPage)
{ {
_trackingPart = hitPart; _trackingPart = hitPart;
_hitPart = hitPart; _hitPart = hitPart;
} }
} }
[self highlight:CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint)]; [self highlight:CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint)];
} }
else if (type == CPPeriodic && CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint)) else if (type == CPPeriodic && CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint))
[self sendAction:[self action] to:[self target]]; [self sendAction:[self action] to:[self target]];
[CPApp setTarget:self selector:@selector(trackScrollButtons:) forNextEventMatchingMask:CPPeriodicMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES]; [CPApp setTarget:self selector:@selector(trackScrollButtons:) forNextEventMatchingMask:CPPeriodicMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
} }
@@ -569,15 +568,15 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
{ {
if (![self isEnabled]) if (![self isEnabled])
return; return;
_hitPart = [self testPart:[anEvent locationInWindow]]; _hitPart = [self testPart:[anEvent locationInWindow]];
switch (_hitPart) switch (_hitPart)
{ {
case CPScrollerKnob: return [self trackKnob:anEvent]; case CPScrollerKnob: return [self trackKnob:anEvent];
case CPScrollerDecrementLine: case CPScrollerDecrementLine:
case CPScrollerIncrementLine: case CPScrollerIncrementLine:
case CPScrollerDecrementPage: case CPScrollerDecrementPage:
case CPScrollerIncrementPage: return [self trackScrollButtons:anEvent]; case CPScrollerIncrementPage: return [self trackScrollButtons:anEvent];
} }
@@ -603,19 +602,32 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
_knobProportion = [aCoder decodeFloatForKey:CPScrollerKnobProportionKey]; _knobProportion = [aCoder decodeFloatForKey:CPScrollerKnobProportionKey];
_partRects = []; _partRects = [];
_hitPart = CPScrollerNoPart; _hitPart = CPScrollerNoPart;
[self _calculateIsVertical]; [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; return self;
} }
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeInt:_controlSize forKey:CPScrollerControlSizeKey]; [aCoder encodeInt:_controlSize forKey:CPScrollerControlSizeKey];
[aCoder encodeFloat:_knobProportion forKey:CPScrollerKnobProportionKey]; [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 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CPButton.j"
@import "CPTextField.j" @import "CPTextField.j"
#include "Platform/Platform.h"
CPSearchFieldRecentsTitleMenuItemTag = 1000; CPSearchFieldRecentsTitleMenuItemTag = 1000;
CPSearchFieldRecentsMenuItemTag = 1001; CPSearchFieldRecentsMenuItemTag = 1001;
CPSearchFieldClearRecentsMenuItemTag = 1002; CPSearchFieldClearRecentsMenuItemTag = 1002;
CPSearchFieldNoRecentsMenuItemTag = 1003; CPSearchFieldNoRecentsMenuItemTag = 1003;
CPSearchFieldSeparatorMenuItemTag = 1004;
var CPSearchFieldSearchImage = nil, var CPSearchFieldSearchImage = nil,
CPSearchFieldFindImage = nil, CPSearchFieldFindImage = nil,
CPSearchFieldCancelImage = nil, CPSearchFieldCancelImage = nil,
CPSearchFieldCancelPressedImage = 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 @ingroup appkit
@class CPSearchField @class CPSearchField
@@ -54,32 +62,37 @@ var CPSearchFieldSearchImage = nil,
int _maximumRecents; int _maximumRecents;
BOOL _sendsWholeSearchString; BOOL _sendsWholeSearchString;
BOOL _sendsSearchStringImmediately; BOOL _sendsSearchStringImmediately;
BOOL _canResignFirstResponder;
CPTimer _partialStringTimer; CPTimer _partialStringTimer;
} }
+ (CPString)defaultThemeClass
{
return @"searchfield"
}
+ (void)initialize + (void)initialize
{ {
if (self != [CPSearchField class]) if (self != [CPSearchField class])
return; return;
var bundle = [CPBundle bundleForClass:self]; var bundle = [CPBundle bundleForClass:self];
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:CGSizeMake(25, 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(25, 22)]; 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(22, 22)]; 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(22, 22)]; CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
} }
- (id)initWithFrame:(CGRect)frame - (id)initWithFrame:(CGRect)frame
{ {
if (self = [super initWithFrame:frame]) if (self = [super initWithFrame:frame])
{ {
_recentSearches = [CPArray array];
_maximumRecents = 10; _maximumRecents = 10;
_sendsWholeSearchString = NO; _sendsWholeSearchString = NO;
_sendsSearchStringImmediately = NO; _sendsSearchStringImmediately = NO;
_recentsAutosaveName = nil; _recentsAutosaveName = nil;
[self _initWithFrame:frame]; [self _init];
#if PLATFORM(DOM) #if PLATFORM(DOM)
_cancelButton._DOMElement.style.cursor = "default"; _cancelButton._DOMElement.style.cursor = "default";
_searchButton._DOMElement.style.cursor = "default"; _searchButton._DOMElement.style.cursor = "default";
@@ -89,23 +102,28 @@ var CPSearchFieldSearchImage = nil,
return self; return self;
} }
- (void)_initWithFrame:(CGRect)frame - (void)_init
{ {
_recentSearches = [CPArray array];
[self setBezeled:YES]; [self setBezeled:YES];
[self setBezelStyle:CPTextFieldRoundedBezel]; [self setBezelStyle:CPTextFieldRoundedBezel];
[self setBordered:YES]; [self setBordered:YES];
[self setEditable:YES]; [self setEditable:YES];
[self setDelegate:self]; [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]; [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 resetSearchButton];
[self addSubview:_searchButton];
_canResignFirstResponder = YES;
} }
// Managing Buttons // Managing Buttons
@@ -115,7 +133,15 @@ var CPSearchFieldSearchImage = nil,
*/ */
- (void)setSearchButton:(CPButton)button - (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 - (void)resetSearchButton
{ {
var searchButtonImage, var button = [self searchButton],
action, searchButtonImage = (_searchMenuTemplate === nil) ? CPSearchFieldSearchImage : CPSearchFieldFindImage;
target,
button = [self searchButton];
if (_searchMenuTemplate === nil)
{
searchButtonImage = CPSearchFieldSearchImage;
action = @selector(_sendAction:);
target = self;
}
else
{
searchButtonImage = CPSearchFieldFindImage;
action = @selector(_showMenu:);
target = self;
}
[button setBordered:NO]; [button setBordered:NO];
[button setImageScaling:CPScaleToFit]; [button setImageScaling:CPScaleToFit];
[button setImage:searchButtonImage]; [button setImage:searchButtonImage];
[button setAutoresizingMask:CPViewMaxXMargin]; [button setAutoresizingMask:CPViewMaxXMargin];
[button setTarget:target];
[button setAction:action];
} }
/*! /*!
@@ -165,7 +174,18 @@ var CPSearchFieldSearchImage = nil,
*/ */
- (void)setCancelButton:(CPButton)button - (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. @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. 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) if (_searchButton)
{ {
var searchRect = [_searchButton frame]; var searchBounds = [self searchButtonRectForBounds:bounds];
leftOffset = searchRect.origin.x + searchRect.size.width; leftOffset = _CGRectGetMaxX(searchBounds) + 2;
} }
if (_cancelButton) if (_cancelButton)
{ {
var cancelRect = [_cancelButton frame]; var cancelRect = [self cancelButtonRectForBounds:bounds];
width = cancelRect.origin.x - leftOffset; 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. @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. 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. @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. 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 - (CGRect)cancelButtonRectForBounds:(CGRect)rect
{ {
return [_cancelButton frame]; 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 // Managing Menu Templates
@@ -254,9 +276,9 @@ var CPSearchFieldSearchImage = nil,
@param menu The menu template to use. @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. 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 resetSearchButton];
[self _loadRecentSearchList]; [self _loadRecentSearchList];
@@ -373,7 +395,7 @@ var CPSearchFieldSearchImage = nil,
// Private methods and subclassing // Private methods and subclassing
- (CPRect)contentRectForBounds:(CPRect)bounds - (CGRect)contentRectForBounds:(CGRect)bounds
{ {
var superbounds = [super contentRectForBounds:bounds]; var superbounds = [super contentRectForBounds:bounds];
return [self searchTextRectForBounds:superbounds]; return [self searchTextRectForBounds:superbounds];
@@ -447,37 +469,78 @@ var CPSearchFieldSearchImage = nil,
[self _updateSearchMenu]; [self _updateSearchMenu];
} }
- (BOOL)trackMouse:(CPEvent)event - (CPView)hitTest:(CGPoint)aPoint
{ {
var rect, // Make sure a hit anywhere within the search field returns the search field itself
point, if (_CGRectContainsPoint([self frame], aPoint))
location = [event locationInWindow]; return self;
else
point = [self convertPoint:location fromView:nil]; return 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];
} }
- (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" Recent Searches
action:NULL 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:@""]; keyEquivalent:@""];
[item setTag:CPSearchFieldRecentsTitleMenuItemTag]; [item setTag:CPSearchFieldRecentsTitleMenuItemTag];
[item setEnabled:NO]; [item setEnabled:NO];
@@ -490,15 +553,15 @@ var CPSearchFieldSearchImage = nil,
[item setTarget:self]; [item setTarget:self];
[template addItem:item]; [template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"Clear recent searches" item = [[CPMenuItem alloc] initWithTitle:@"Clear Recent Searches"
action:@selector(_searchFieldClearRecents:) action:@selector(_searchFieldClearRecents:)
keyEquivalent:@""]; keyEquivalent:@""];
[item setTag:CPSearchFieldClearRecentsMenuItemTag]; [item setTag:CPSearchFieldClearRecentsMenuItemTag];
[item setTarget:self]; [item setTarget:self];
[template addItem:item]; [template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"No recent searches" item = [[CPMenuItem alloc] initWithTitle:@"No Recent Searches"
action:NULL action:nil
keyEquivalent:@""]; keyEquivalent:@""];
[item setTag:CPSearchFieldNoRecentsMenuItemTag]; [item setTag:CPSearchFieldNoRecentsMenuItemTag];
[item setEnabled:NO]; [item setEnabled:NO];
@@ -512,61 +575,96 @@ var CPSearchFieldSearchImage = nil,
if (_searchMenuTemplate === nil) if (_searchMenuTemplate === nil)
return; return;
var i, menu = [[CPMenu alloc] init], var menu = [[CPMenu alloc] init],
countOfRecents = [_recentSearches count], countOfRecents = [_recentSearches count],
numberOfItems = [_searchMenuTemplate numberOfItems]; numberOfItems = [_searchMenuTemplate numberOfItems];
for (i = 0; i < numberOfItems; i++) for (var i = 0; i < numberOfItems; i++)
{ {
var item = [_searchMenuTemplate itemAtIndex:i], var item = [[_searchMenuTemplate itemAtIndex:i] copy];
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;
}
if (tag === CPSearchFieldClearRecentsMenuItemTag || tag === CPSearchFieldRecentsTitleMenuItemTag) switch ([item tag])
{
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)
{ {
var j; case CPSearchFieldRecentsTitleMenuItemTag:
for (j = 0; j < countOfRecents; j++) if (countOfRecents === 0)
continue;
if ([menu numberOfItems] > 0)
[self _addSeparatorToMenu:menu];
break;
case CPSearchFieldRecentsMenuItemTag:
{ {
var rencentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j] var itemAction = @selector(_searchFieldSearch:);
action:@selector(_searchFieldSearch:)
keyEquivalent:[item keyEquivalent]]; for (var recentIndex = 0; recentIndex < countOfRecents; ++recentIndex)
[rencentItem setTarget:self]; {
[menu addItem:rencentItem]; // 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; _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]) if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled])
return; 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]; 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 - (void)_sendPartialString
{ {
[[self target] performSelector:[self action] withObject:self]; [super sendAction:[self action] to:[self target]];
[_partialStringTimer invalidate];
} }
- (void)_searchFieldCancel:(id)sender - (void)_searchFieldCancel:(id)sender
@@ -593,14 +693,15 @@ var CPSearchFieldSearchImage = nil,
- (void)_searchFieldSearch:(id)sender - (void)_searchFieldSearch:(id)sender
{ {
var searchString = [sender title]; var searchString = [[sender title] substringFromIndex:[RECENT_SEARCH_PREFIX length]];
if ([sender tag] != CPSearchFieldRecentsMenuItemTag) if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
[self _addStringToRecentSearches:searchString]; [self _addStringToRecentSearches:searchString];
[self setObjectValue:searchString]; [self setObjectValue:searchString];
[self _sendPartialString]; [self _sendPartialString];
[self selectAll:nil];
[self _updateCancelButtonVisibility]; [self _updateCancelButtonVisibility];
} }
@@ -608,6 +709,8 @@ var CPSearchFieldSearchImage = nil,
{ {
[self setRecentSearches:[CPArray array]]; [self setRecentSearches:[CPArray array]];
[self _updateSearchMenu]; [self _updateSearchMenu];
[self setStringValue:@""];
[self _updateCancelButtonVisibility];
} }
- (void)_registerForAutosaveNotification - (void)_registerForAutosaveNotification
@@ -668,7 +771,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey", CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey", CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
CPMaximumRecentsKey = @"CPMaximumRecentsKey", CPMaximumRecentsKey = @"CPMaximumRecentsKey",
CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey"; CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey";
@implementation CPSearchField (CPCoding) @implementation CPSearchField (CPCoding)
@@ -690,6 +793,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
if (_recentsAutosaveName) if (_recentsAutosaveName)
[coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey]; [coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
if (_searchMenuTemplate) if (_searchMenuTemplate)
[coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey]; [coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
} }
@@ -698,18 +802,17 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
{ {
if (self = [super initWithCoder:coder]) if (self = [super initWithCoder:coder])
{ {
[self _initWithFrame:[self frame]];
_recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey]; _recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey];
_sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey]; _sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
_sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey]; _sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
_maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey]; _maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey];
var template = [coder decodeObjectForKey:CPSearchMenuTemplateKey]; var template = [coder decodeObjectForKey:CPSearchMenuTemplateKey];
if (template) if (template)
[self setSearchMenuTemplate:template]; [self setSearchMenuTemplate:template];
[self setDelegate:self]; [self _init];
} }
return self; return self;
+1
View File
@@ -1,6 +1,7 @@
@import "CPTextField.j" @import "CPTextField.j"
/*! /*!
@ingroup appkit @ingroup appkit
*/ */
+132 -133
View File
@@ -24,13 +24,12 @@
@import "CPControl.j" @import "CPControl.j"
#include "CoreGraphics/CGGeometry.h"
CPSegmentSwitchTrackingSelectOne = 0; CPSegmentSwitchTrackingSelectOne = 0;
CPSegmentSwitchTrackingSelectAny = 1; CPSegmentSwitchTrackingSelectAny = 1;
CPSegmentSwitchTrackingMomentary = 2; CPSegmentSwitchTrackingMomentary = 2;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPSegmentedControl @class CPSegmentedControl
@@ -49,7 +48,7 @@ CPSegmentSwitchTrackingMomentary = 2;
BOOL _trackingHighlighted; BOOL _trackingHighlighted;
} }
+ (CPString)themeClass + (CPString)defaultThemeClass
{ {
return "segmented-control"; return "segmented-control";
} }
@@ -64,16 +63,16 @@ CPSegmentSwitchTrackingMomentary = 2;
{ {
_segments = []; _segments = [];
_themeStates = []; _themeStates = [];
self = [super initWithFrame:aRect]; self = [super initWithFrame:aRect];
if (self) if (self)
{ {
_selectedSegment = -1; _selectedSegment = -1;
_trackingMode = CPSegmentSwitchTrackingSelectOne; _trackingMode = CPSegmentSwitchTrackingSelectOne;
} }
return self; return self;
} }
@@ -82,7 +81,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (int)selectedTag - (int)selectedTag
{ {
return _segments[_selectedSegment].tag; return [_segments[_selectedSegment] tag];
} }
// Specifying the number of segments // Specifying the number of segments
@@ -94,11 +93,11 @@ CPSegmentSwitchTrackingMomentary = 2;
{ {
if (_segments.length == aCount) if (_segments.length == aCount)
return; return;
var height = CGRectGetHeight([self bounds]); var height = CGRectGetHeight([self bounds]);
if (_segments.length < aCount) if (_segments.length < aCount)
{ {
for (var index = _segments.length; index < aCount; ++index) for (var index = _segments.length; index < aCount; ++index)
{ {
_segments[index] = [[_CPSegmentItem alloc] init]; _segments[index] = [[_CPSegmentItem alloc] init];
@@ -151,15 +150,15 @@ CPSegmentSwitchTrackingMomentary = 2;
- (BOOL)selectSegmentWithTag:(int)aTag - (BOOL)selectSegmentWithTag:(int)aTag
{ {
var index = 0; var index = 0;
for (; index < _segments.length; ++index) for (; index < _segments.length; ++index)
if (_segments[index].tag == aTag) if (_segments[index].tag == aTag)
{ {
[self setSelectedSegment:index]; [self setSelectedSegment:index];
return YES; return YES;
} }
return NO; return NO;
} }
@@ -174,28 +173,28 @@ CPSegmentSwitchTrackingMomentary = 2;
{ {
if (_trackingMode == aTrackingMode) if (_trackingMode == aTrackingMode)
return; return;
_trackingMode = aTrackingMode; _trackingMode = aTrackingMode;
if (_trackingMode == CPSegmentSwitchTrackingSelectOne) if (_trackingMode == CPSegmentSwitchTrackingSelectOne)
{ {
var index = 0, var index = 0,
selected = NO; selected = NO;
for (; index < _segments.length; ++index) for (; index < _segments.length; ++index)
if (_segments[index].selected) if ([_segments[index] selected])
if (selected) if (selected)
[self setSelected:NO forSegment:index]; [self setSelected:NO forSegment:index];
else else
selected = YES; selected = YES;
} }
else if (_trackingMode == CPSegmentSwitchTrackingMomentary) else if (_trackingMode == CPSegmentSwitchTrackingMomentary)
{ {
var index = 0; var index = 0;
for (; index < _segments.length; ++index) for (; index < _segments.length; ++index)
if (_segments[index].selected) if ([_segments[index] selected])
[self setSelected:NO forSegment:index]; [self setSelected:NO forSegment:index];
} }
} }
@@ -217,8 +216,8 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment - (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
{ {
_segments[aSegment].width = aWidth; [_segments[aSegment] setWidth:aWidth];
[self tileWithChangedSegment:aSegment]; [self tileWithChangedSegment:aSegment];
} }
@@ -229,7 +228,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (float)widthForSegment:(unsigned)aSegment - (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 - (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
{ {
var segment = _segments[aSegment]; [_segments[aSegment] setImage:anImage];
segment.image = anImage;
[self tileWithChangedSegment:aSegment]; [self tileWithChangedSegment:aSegment];
} }
@@ -254,7 +251,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (CPImage)imageForSegment:(unsigned)aSegment - (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 - (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
{ {
var segment = _segments[aSegment]; [_segments[aSegment] setLabel:aLabel];
_segments[aSegment].label = aLabel;
[self tileWithChangedSegment:aSegment]; [self tileWithChangedSegment:aSegment];
} }
@@ -279,7 +274,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (CPString)labelForSegment:(unsigned)aSegment - (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 - (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 - (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 - (void)setSelected:(BOOL)isSelected forSegment:(unsigned)aSegment
{ {
var segment = _segments[aSegment]; var segment = _segments[aSegment];
// If we're already in this state, bail. // If we're already in this state, bail.
if (segment.selected == isSelected) if ([segment selected] == isSelected)
return; return;
segment.selected = isSelected; [segment setSelected:isSelected];
_themeStates[aSegment] = isSelected ? CPThemeStateSelected : CPThemeStateNormal; _themeStates[aSegment] = isSelected ? CPThemeStateSelected : CPThemeStateNormal;
@@ -326,18 +321,18 @@ CPSegmentSwitchTrackingMomentary = 2;
if (isSelected) if (isSelected)
{ {
var oldSelectedSegment = _selectedSegment; var oldSelectedSegment = _selectedSegment;
_selectedSegment = aSegment; _selectedSegment = aSegment;
if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1) if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1)
{ {
_segments[oldSelectedSegment].selected = NO; [_segments[oldSelectedSegment] setSelected:NO];
_themeStates[oldSelectedSegment] = CPThemeStateNormal; _themeStates[oldSelectedSegment] = CPThemeStateNormal;
[self drawSegmentBezel:oldSelectedSegment highlight:NO]; [self drawSegmentBezel:oldSelectedSegment highlight:NO];
} }
} }
if (_trackingMode != CPSegmentSwitchTrackingMomentary) if (_trackingMode != CPSegmentSwitchTrackingMomentary)
[self drawSegmentBezel:aSegment highlight:NO]; [self drawSegmentBezel:aSegment highlight:NO];
@@ -352,7 +347,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (BOOL)isSelectedForSegment:(unsigned)aSegment - (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 - (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
{ {
[_segments[aSegment] setEnabled:isEnabled];
if (isEnabled) if (isEnabled)
_themeStates[aSegment] &= ~CPThemeStateDisabled; _themeStates[aSegment] &= ~CPThemeStateDisabled;
else else
@@ -379,7 +376,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (BOOL)isEnabledForSegment:(unsigned)aSegment - (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 - (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 - (int)tagForSegment:(unsigned)aSegment
{ {
return _segments[aSegment].tag; return [_segments[aSegment] tag];
} }
// Drawings // Drawings
@@ -461,7 +458,7 @@ CPSegmentSwitchTrackingMomentary = 2;
else if (aName.indexOf("segment-bezel") === 0) else if (aName.indexOf("segment-bezel") === 0)
{ {
var segment = parseInt(aName.substring("segment-bezel-".length), 10), var segment = parseInt(aName.substring("segment-bezel-".length), 10),
frame = CGRectCreateCopy(_segments[segment].frame); frame = CGRectCreateCopy([_segments[segment] frame]);
if (segment === 0) if (segment === 0)
{ {
@@ -495,7 +492,7 @@ CPSegmentSwitchTrackingMomentary = 2;
- (CPView)createEphemeralSubviewNamed:(CPString)aName - (CPView)createEphemeralSubviewNamed:(CPString)aName
{ {
if (aName.substring(0, "segment-content".length) == "segment-content") if ([aName hasPrefix:@"segment-content"])
return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()]; return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
return [[CPView alloc] initWithFrame:_CGRectMakeZero()]; return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
@@ -510,10 +507,10 @@ CPSegmentSwitchTrackingMomentary = 2;
themeState |= _themeState & CPThemeStateDisabled; themeState |= _themeState & CPThemeStateDisabled;
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color" var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
inState:themeState]; inState:themeState],
var leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel" leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
positioned:CPWindowBelow positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil]; relativeToEphemeralSubviewNamed:nil];
@@ -523,41 +520,39 @@ CPSegmentSwitchTrackingMomentary = 2;
themeState |= _themeState & CPThemeStateDisabled; themeState |= _themeState & CPThemeStateDisabled;
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color" var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
inState:themeState]; inState:themeState],
var rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel" rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
positioned:CPWindowBelow positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil]; relativeToEphemeralSubviewNamed:nil];
[rightBezelView setBackgroundColor:rightCapColor]; [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]; var themeState = _themeStates[i];
themeState |= _themeState & CPThemeStateDisabled; themeState |= _themeState & CPThemeStateDisabled;
var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color" var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color"
inState:themeState]; inState:themeState],
var bezelView = [self layoutEphemeralSubviewNamed:"segment-bezel-"+i bezelView = [self layoutEphemeralSubviewNamed:"segment-bezel-" + i
positioned:CPWindowBelow positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil]; relativeToEphemeralSubviewNamed:nil];
[bezelView setBackgroundColor:bezelColor]; [bezelView setBackgroundColor:bezelColor];
//layout image/title views // layout image/title views
var segment = _segments[i]; var segment = _segments[i],
contentView = [self layoutEphemeralSubviewNamed:@"segment-content-" + i
var contentView = [self layoutEphemeralSubviewNamed:@"segment-content-"+i
positioned:CPWindowAbove positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"segment-bezel-"+i]; relativeToEphemeralSubviewNamed:@"segment-bezel-" + i];
[contentView setText:segment.label]; [contentView setText:[segment label]];
[contentView setImage:segment.image]; [contentView setImage:[segment image]];
[contentView setFont:[self valueForThemeAttribute:@"font" inState:themeState]]; [contentView setFont:[self valueForThemeAttribute:@"font" inState:themeState]];
[contentView setTextColor:[self valueForThemeAttribute:@"text-color" 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 setLineBreakMode:[self valueForThemeAttribute:@"line-break-mode" inState:themeState]];
[contentView setTextShadowColor:[self valueForThemeAttribute:@"text-shadow-color" inState:themeState]]; [contentView setTextShadowColor:[self valueForThemeAttribute:@"text-shadow-color" inState:themeState]];
[contentView setTextShadowOffset:[self valueForThemeAttribute:@"text-shadow-offset" inState:themeState]]; [contentView setTextShadowOffset:[self valueForThemeAttribute:@"text-shadow-offset" inState:themeState]];
[contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" inState:themeState]]; [contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" inState:themeState]];
if (segment.image && segment.label) if ([segment image] && [segment label])
[contentView setImagePosition:[self valueForThemeAttribute:@"image-position" inState:themeState]]; [contentView setImagePosition:[self valueForThemeAttribute:@"image-position" inState:themeState]];
else if (segment.image) else if ([segment image])
[contentView setImagePosition:CPImageOnly]; [contentView setImagePosition:CPImageOnly];
if (i == count - 1) if (i == count - 1)
continue; continue;
var borderState = _themeStates[i] | _themeStates[i+1]; var borderState = _themeStates[i] | _themeStates[i + 1];
borderState = (borderState & CPThemeStateSelected & ~CPThemeStateHighlighted) ? CPThemeStateSelected : CPThemeStateNormal; borderState = (borderState & CPThemeStateSelected & ~CPThemeStateHighlighted) ? CPThemeStateSelected : CPThemeStateNormal;
borderState |= _themeState & CPThemeStateDisabled; borderState |= _themeState & CPThemeStateDisabled;
var borderColor = [self valueForThemeAttribute:@"divider-bezel-color" var borderColor = [self valueForThemeAttribute:@"divider-bezel-color"
inState:borderState]; inState:borderState],
var borderView = [self layoutEphemeralSubviewNamed:"divider-bezel-"+i borderView = [self layoutEphemeralSubviewNamed:"divider-bezel-" + i
positioned:CPWindowBelow positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil]; relativeToEphemeralSubviewNamed:nil];
[borderView setBackgroundColor:borderColor]; [borderView setBackgroundColor:borderColor];
@@ -609,48 +604,53 @@ CPSegmentSwitchTrackingMomentary = 2;
return; return;
var segment = _segments[aSegment], var segment = _segments[aSegment],
segmentWidth = segment.width, segmentWidth = [segment width],
themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled), themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled),
contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState], contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState],
font = [self valueForThemeAttribute:@"font" inState:themeState]; font = [self valueForThemeAttribute:@"font" inState:themeState];
if (!segmentWidth) if (!segmentWidth)
{ {
if (segment.image && segment.label) if ([segment image] && [segment label])
segmentWidth = [segment.label sizeWithFont:font].width + [segment.image size].width + contentInset.left + contentInset.right; segmentWidth = [[segment label] sizeWithFont:font].width + [[segment image] size].width + contentInset.left + contentInset.right;
else if (segment.image) 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) 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 else
segmentWidth = 0.0; segmentWidth = 0.0;
} }
var delta = segmentWidth - CGRectGetWidth(segment.frame); var delta = segmentWidth - CGRectGetWidth([segment frame]);
if (!delta) if (!delta)
return; {
[self setNeedsLayout];
[self setNeedsDisplay:YES];
// Update Contorl Size return;
}
// Update control size
var frame = [self frame]; var frame = [self frame];
[self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))]; [self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))];
// Update Segment Width // Update segment width
segment.width = segmentWidth; [segment setWidth:segmentWidth];
segment.frame = [self frameForSegment:aSegment];; [segment setFrame:[self frameForSegment:aSegment]];
// Update Following Segments Widths // Update following segments widths
var index = aSegment + 1; var index = aSegment + 1;
for (; index < _segments.length; ++index) for (; index < _segments.length; ++index)
{ {
_segments[index].frame.origin.x += delta; [_segments[index] frame].origin.x += delta;
[self drawSegmentBezel:index highlight:NO]; [self drawSegmentBezel:index highlight:NO];
[self drawSegment:index highlight:NO]; [self drawSegment:index highlight:NO];
} }
[self drawSegmentBezel:aSegment highlight:NO]; [self drawSegmentBezel:aSegment highlight:NO];
[self drawSegment:aSegment highlight:NO]; [self drawSegment:aSegment highlight:NO];
@@ -696,14 +696,14 @@ CPSegmentSwitchTrackingMomentary = 2;
{ {
var location = [self convertPoint:aPoint fromView:nil], var location = [self convertPoint:aPoint fromView:nil],
count = _segments.length; count = _segments.length;
while (count--) while (count--)
if (CGRectContainsPoint(_segments[count].frame, aPoint)) if (CGRectContainsPoint([_segments[count] frame], aPoint))
return count; return count;
if (_segments.length) 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; adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x;
if (CGRectContainsPoint(adjustedLastFrame, aPoint)) if (CGRectContainsPoint(adjustedLastFrame, aPoint))
@@ -717,7 +717,7 @@ CPSegmentSwitchTrackingMomentary = 2;
{ {
if (![self isEnabled]) if (![self isEnabled])
return; return;
[self trackSegment:anEvent]; [self trackSegment:anEvent];
} }
@@ -731,10 +731,10 @@ CPSegmentSwitchTrackingMomentary = 2;
@param anEvent the event to handle @param anEvent the event to handle
*/ */
- (void)trackSegment:(CPEvent)anEvent - (void)trackSegment:(CPEvent)anEvent
{ {
var type = [anEvent type], var type = [anEvent type],
location = [self convertPoint:[anEvent locationInWindow] fromView:nil]; location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if (type == CPLeftMouseUp) if (type == CPLeftMouseUp)
{ {
if (_trackingSegment == -1) if (_trackingSegment == -1)
@@ -745,30 +745,30 @@ CPSegmentSwitchTrackingMomentary = 2;
if (_trackingMode == CPSegmentSwitchTrackingSelectAny) if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
{ {
[self setSelected:![self isSelectedForSegment:_trackingSegment] forSegment:_trackingSegment]; [self setSelected:![self isSelectedForSegment:_trackingSegment] forSegment:_trackingSegment];
// With ANY, _selectedSegment means last pressed. // With ANY, _selectedSegment means last pressed.
_selectedSegment = _trackingSegment; _selectedSegment = _trackingSegment;
} }
else else
[self setSelected:YES forSegment:_trackingSegment]; [self setSelected:YES forSegment:_trackingSegment];
[self sendAction:[self action] to:[self target]]; [self sendAction:[self action] to:[self target]];
if (_trackingMode == CPSegmentSwitchTrackingMomentary) if (_trackingMode == CPSegmentSwitchTrackingMomentary)
{ {
[self setSelected:NO forSegment:_trackingSegment]; [self setSelected:NO forSegment:_trackingSegment];
_selectedSegment = -1; _selectedSegment = -1;
} }
} }
[self drawSegmentBezel:_trackingSegment highlight:NO]; [self drawSegmentBezel:_trackingSegment highlight:NO];
_trackingSegment = -1; _trackingSegment = -1;
return; return;
} }
if (type == CPLeftMouseDown) if (type == CPLeftMouseDown)
{ {
var trackingSegment = [self testSegment:location]; var trackingSegment = [self testSegment:location];
@@ -779,7 +779,7 @@ CPSegmentSwitchTrackingMomentary = 2;
[self drawSegmentBezel:_trackingSegment highlight:YES]; [self drawSegmentBezel:_trackingSegment highlight:YES];
} }
} }
else if (type == CPLeftMouseDragged) else if (type == CPLeftMouseDragged)
{ {
if (_trackingSegment == -1) if (_trackingSegment == -1)
@@ -793,14 +793,14 @@ CPSegmentSwitchTrackingMomentary = 2;
[self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted]; [self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
} }
} }
[CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES]; [CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
} }
- (void)setFont:(CPFont)aFont - (void)setFont:(CPFont)aFont
{ {
[super setFont:aFont]; [super setFont:aFont];
[self tileWithChangedSegment:0]; [self tileWithChangedSegment:0];
} }
@@ -816,12 +816,12 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super initWithCoder:aCoder]; self = [super initWithCoder:aCoder];
if (self) if (self)
{ {
var frame = [self frame], var frame = [self frame],
originalWidth = frame.size.width; originalWidth = frame.size.width;
frame.size.width = 0; frame.size.width = 0;
[self setFrame:frame]; [self setFrame:frame];
@@ -832,38 +832,38 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
if ([aCoder containsValueForKey:CPSegmentedControlSelectedKey]) if ([aCoder containsValueForKey:CPSegmentedControlSelectedKey])
_selectedSegment = [aCoder decodeIntForKey:CPSegmentedControlSelectedKey]; _selectedSegment = [aCoder decodeIntForKey:CPSegmentedControlSelectedKey];
else else
_selectedSegment = -1; _selectedSegment = -1;
if ([aCoder containsValueForKey:CPSegmentedControlTrackingModeKey]) if ([aCoder containsValueForKey:CPSegmentedControlTrackingModeKey])
_trackingMode = [aCoder decodeIntForKey:CPSegmentedControlTrackingModeKey]; _trackingMode = [aCoder decodeIntForKey:CPSegmentedControlTrackingModeKey];
else else
_trackingMode = CPSegmentSwitchTrackingSelectOne; _trackingMode = CPSegmentSwitchTrackingSelectOne;
// HACK // HACK
for (var i = 0; i < _segments.length; i++) 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]; [self tileWithChangedSegment:i];
} }
var difference = MAX(originalWidth - [self frame].size.width, 0.0), var difference = MAX(originalWidth - [self frame].size.width, 0.0),
remainingWidth = FLOOR(difference / _segments.length); remainingWidth = FLOOR(difference / _segments.length);
for (var i=0; i < _segments.length; i++) for (var i = 0; i < _segments.length; i++)
[self setWidth:_segments[i].width + remainingWidth forSegment:i]; [self setWidth:[_segments[i] width] + remainingWidth forSegment:i];
[self tileWithChangedSegment:0]; [self tileWithChangedSegment:0];
} }
return self; return self;
} }
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeObject:_segments forKey:CPSegmentedControlSegmentsKey]; [aCoder encodeObject:_segments forKey:CPSegmentedControlSegmentsKey];
[aCoder encodeInt:_selectedSegment forKey:CPSegmentedControlSelectedKey]; [aCoder encodeInt:_selectedSegment forKey:CPSegmentedControlSelectedKey];
[aCoder encodeInt:_segmentStyle forKey:CPSegmentedControlSegmentStyleKey]; [aCoder encodeInt:_segmentStyle forKey:CPSegmentedControlSegmentStyleKey];
@@ -875,15 +875,15 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
@implementation _CPSegmentItem : CPObject @implementation _CPSegmentItem : CPObject
{ {
CPImage image; CPImage image @accessors;
CPString label; CPString label @accessors;
CPMenu menu; CPMenu menu @accessors;
BOOL selected; BOOL selected @accessors;
BOOL enabled; BOOL enabled @accessors;
int tag; int tag @accessors;
int width; int width @accessors;
CGRect frame; CGRect frame @accessors;
} }
- (id)init - (id)init
@@ -894,8 +894,8 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
label = @""; label = @"";
menu = nil; menu = nil;
selected = NO; selected = NO;
enabled = NO; enabled = YES;
tag = 0; tag = -1;
width = 0; width = 0;
frame = CGRectMakeZero(); frame = CGRectMakeZero();
@@ -918,7 +918,7 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
image = [aCoder decodeObjectForKey:CPSegmentItemImageKey]; image = [aCoder decodeObjectForKey:CPSegmentItemImageKey];
@@ -931,7 +931,7 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
frame = CGRectMakeZero(); frame = CGRectMakeZero();
} }
return self; return self;
} }
@@ -947,4 +947,3 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
} }
@end @end
+41 -18
View File
@@ -28,19 +28,17 @@
@import "CPView.j" @import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
CPLightShadow = 0; CPLightShadow = 0;
CPHeavyShadow = 1; CPHeavyShadow = 1;
var CPShadowViewLightBackgroundColor = nil, var CPShadowViewLightBackgroundColor = nil,
CPShadowViewHeavyBackgroundColor = nil; CPShadowViewHeavyBackgroundColor = nil;
var LIGHT_LEFT_INSET = 3.0, var LIGHT_LEFT_INSET = 3.0,
LIGHT_RIGHT_INSET = 3.0, LIGHT_RIGHT_INSET = 3.0,
LIGHT_TOP_INSET = 3.0, LIGHT_TOP_INSET = 3.0,
LIGHT_BOTTOM_INSET = 5.0, LIGHT_BOTTOM_INSET = 5.0,
HEAVY_LEFT_INSET = 7.0, HEAVY_LEFT_INSET = 7.0,
HEAVY_RIGHT_INSET = 7.0, HEAVY_RIGHT_INSET = 7.0,
HEAVY_TOP_INSET = 5.0, HEAVY_TOP_INSET = 5.0,
@@ -61,51 +59,76 @@ var LIGHT_LEFT_INSET = 3.0,
return; return;
var bundle = [CPBundle bundleForClass:[self class]]; var bundle = [CPBundle bundleForClass:[self class]];
CPShadowViewLightBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices: 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/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/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/CPShadowViewLightTopRight.png"] size:CGSizeMake(9.0, 9.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightLeft.png"] size:CGSizeMake(9.0, 1.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightLeft.png"] size:CGSizeMake(9.0, 1.0)],
nil, nil,
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightRight.png"] size:CGSizeMake(9.0, 1.0)], [[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/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/CPShadowViewLightBottom.png"] size:CGSizeMake(1.0, 9.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomRight.png"] size:CGSizeMake(9.0, 9.0)] [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomRight.png"] size:CGSizeMake(9.0, 9.0)]
]]]; ]]];
CPShadowViewHeavyBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices: 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/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/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/CPShadowViewHeavyTopRight.png"] size:CGSizeMake(17.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyLeft.png"] size:CGSizeMake(17.0, 1.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyLeft.png"] size:CGSizeMake(17.0, 1.0)],
nil, nil,
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyRight.png"] size:CGSizeMake(17.0, 1.0)], [[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/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/CPShadowViewHeavyBottom.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomRight.png"] size:CGSizeMake(17.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 - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
_weight = CPLightShadow; _weight = CPLightShadow;
[self setBackgroundColor:CPShadowViewLightBackgroundColor]; [self setBackgroundColor:CPShadowViewLightBackgroundColor];
[self setHitTests:NO]; [self setHitTests:NO];
} }
return self; return self;
} }
@@ -113,9 +136,9 @@ var LIGHT_LEFT_INSET = 3.0,
{ {
if (_weight == aWeight) if (_weight == aWeight)
return; return;
_weight = aWeight; _weight = aWeight;
if (_weight == CPLightShadow) if (_weight == CPLightShadow)
[self setBackgroundColor:CPShadowViewLightBackgroundColor]; [self setBackgroundColor:CPShadowViewLightBackgroundColor];
@@ -147,7 +170,7 @@ var LIGHT_LEFT_INSET = 3.0,
{ {
if (_weight == CPLightShadow) if (_weight == CPLightShadow)
return LIGHT_LEFT_INSET + LIGHT_RIGHT_INSET; return LIGHT_LEFT_INSET + LIGHT_RIGHT_INSET;
return HEAVY_LEFT_INSET + HEAVY_RIGHT_INSET; return HEAVY_LEFT_INSET + HEAVY_RIGHT_INSET;
} }
@@ -155,7 +178,7 @@ var LIGHT_LEFT_INSET = 3.0,
{ {
if (_weight == CPLightShadow) if (_weight == CPLightShadow)
return LIGHT_TOP_INSET + LIGHT_BOTTOM_INSET; return LIGHT_TOP_INSET + LIGHT_BOTTOM_INSET;
return HEAVY_TOP_INSET + HEAVY_BOTTOM_INSET; return HEAVY_TOP_INSET + HEAVY_BOTTOM_INSET;
} }
+50 -40
View File
@@ -22,7 +22,6 @@
@import "CPControl.j" @import "CPControl.j"
#include "CoreGraphics/CGGeometry.h"
/*! SLIDER STATES */ /*! SLIDER STATES */
@@ -42,7 +41,7 @@ CPCircularSlider = 1;
BOOL _isVertical; BOOL _isVertical;
} }
+ (CPString)themeClass + (CPString)defaultThemeClass
{ {
return "slider"; return "slider";
} }
@@ -61,14 +60,14 @@ CPCircularSlider = 1;
{ {
_minValue = 0.0; _minValue = 0.0;
_maxValue = 100.0; _maxValue = 100.0;
[self setObjectValue:50.0]; [self setObjectValue:50.0];
[self setContinuous:YES]; [self setContinuous:YES];
[self _recalculateIsVertical]; [self _recalculateIsVertical];
} }
return self; return self;
} }
@@ -76,11 +75,11 @@ CPCircularSlider = 1;
{ {
if (_minValue === aMinimumValue) if (_minValue === aMinimumValue)
return; return;
_minValue = aMinimumValue; _minValue = aMinimumValue;
var doubleValue = [self doubleValue]; var doubleValue = [self doubleValue];
if (doubleValue < _minValue) if (doubleValue < _minValue)
[self setDoubleValue:_minValue]; [self setDoubleValue:_minValue];
@@ -98,11 +97,11 @@ CPCircularSlider = 1;
{ {
if (_maxValue === aMaximumValue) if (_maxValue === aMaximumValue)
return; return;
_maxValue = aMaximumValue; _maxValue = aMaximumValue;
var doubleValue = [self doubleValue]; var doubleValue = [self doubleValue];
if (doubleValue > _maxValue) if (doubleValue > _maxValue)
[self setDoubleValue:_maxValue]; [self setDoubleValue:_maxValue];
@@ -169,27 +168,27 @@ CPCircularSlider = 1;
bounds.size.height = trackWidth; bounds.size.height = trackWidth;
} }
} }
return bounds; return bounds;
} }
- (CGRect)knobRectForBounds:(CGRect)bounds - (CGRect)knobRectForBounds:(CGRect)bounds
{ {
var knobSize = [self currentValueForThemeAttribute:@"knob-size"]; var knobSize = [self currentValueForThemeAttribute:@"knob-size"];
if (knobSize.width <= 0 || knobSize.height <= 0) if (knobSize.width <= 0 || knobSize.height <= 0)
return _CGRectMakeZero(); return _CGRectMakeZero();
var knobRect = _CGRectMake(0.0, 0.0, knobSize.width, knobSize.height), var knobRect = _CGRectMake(0.0, 0.0, knobSize.width, knobSize.height),
trackRect = [self trackRectForBounds:bounds]; trackRect = [self trackRectForBounds:bounds];
// No track, do our best to approximate a place for this thing. // No track, do our best to approximate a place for this thing.
if (!trackRect || _CGRectIsEmpty(trackRect)) if (!trackRect || _CGRectIsEmpty(trackRect))
trackRect = bounds; trackRect = bounds;
if ([self hasThemeState:CPThemeStateCircular]) 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; radius = CGRectGetWidth(trackRect) / 2.0 - 8.0;
knobRect.origin.x = radius * COS(angle) + CGRectGetMidX(trackRect) - 3.0; knobRect.origin.x = radius * COS(angle) + CGRectGetMidX(trackRect) - 3.0;
@@ -198,7 +197,7 @@ CPCircularSlider = 1;
else if ([self isVertical]) else if ([self isVertical])
{ {
knobRect.origin.x = _CGRectGetMidX(trackRect) - knobSize.width / 2.0; 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 else
{ {
@@ -213,10 +212,10 @@ CPCircularSlider = 1;
{ {
if (aName === "track-view") if (aName === "track-view")
return [self trackRectForBounds:[self bounds]]; return [self trackRectForBounds:[self bounds]];
else if (aName === "knob-view") else if (aName === "knob-view")
return [self knobRectForBounds:[self bounds]]; return [self knobRectForBounds:[self bounds]];
return [super rectForEphemeralSubviewNamed:aName]; return [super rectForEphemeralSubviewNamed:aName];
} }
@@ -225,12 +224,12 @@ CPCircularSlider = 1;
if (aName === "track-view" || aName === "knob-view") if (aName === "track-view" || aName === "knob-view")
{ {
var view = [[CPView alloc] init]; var view = [[CPView alloc] init];
[view setHitTests:NO]; [view setHitTests:NO];
return view; return view;
} }
return [super createEphemeralSubviewNamed:aName]; return [super createEphemeralSubviewNamed:aName];
} }
@@ -256,7 +255,7 @@ CPCircularSlider = 1;
var bounds = [self bounds], var bounds = [self bounds],
width = _CGRectGetWidth(bounds), width = _CGRectGetWidth(bounds),
height = _CGRectGetHeight(bounds); height = _CGRectGetHeight(bounds);
_isVertical = width < height ? 1 : (width > height ? 0 : -1); _isVertical = width < height ? 1 : (width > height ? 0 : -1);
if (_isVertical === 1) if (_isVertical === 1)
@@ -282,7 +281,7 @@ CPCircularSlider = 1;
var knobView = [self layoutEphemeralSubviewNamed:@"knob-view" var knobView = [self layoutEphemeralSubviewNamed:@"knob-view"
positioned:CPWindowAbove positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"track-view"]; relativeToEphemeralSubviewNamed:@"track-view"];
if (knobView) if (knobView)
[knobView setBackgroundColor:[self currentValueForThemeAttribute:"knob-color"]]; [knobView setBackgroundColor:[self currentValueForThemeAttribute:"knob-color"]];
} }
@@ -320,7 +319,7 @@ CPCircularSlider = 1;
var minValue = [self minValue]; 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 else
{ {
@@ -339,44 +338,43 @@ CPCircularSlider = 1;
{ {
var bounds = [self bounds], var bounds = [self bounds],
knobRect = [self knobRectForBounds:_CGRectMakeCopy(bounds)]; knobRect = [self knobRectForBounds:_CGRectMakeCopy(bounds)];
if (_CGRectContainsPoint(knobRect, aPoint)) if (_CGRectContainsPoint(knobRect, aPoint))
_dragOffset = _CGSizeMake(_CGRectGetMidX(knobRect) - aPoint.x, _CGRectGetMidY(knobRect) - aPoint.y); _dragOffset = _CGSizeMake(_CGRectGetMidX(knobRect) - aPoint.x, _CGRectGetMidY(knobRect) - aPoint.y);
else
else
{ {
var trackRect = [self trackRectForBounds:bounds]; var trackRect = [self trackRectForBounds:bounds];
if (trackRect && _CGRectContainsPoint(trackRect, aPoint)) if (trackRect && _CGRectContainsPoint(trackRect, aPoint))
{ {
_dragOffset = _CGSizeMakeZero(); _dragOffset = _CGSizeMakeZero();
[self setObjectValue:[self _valueAtPoint:aPoint]]; [self setObjectValue:[self _valueAtPoint:aPoint]];
} }
else else
return NO; return NO;
} }
[self setHighlighted:YES]; [self setHighlighted:YES];
[self setNeedsLayout]; [self setNeedsLayout];
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
return YES; return YES;
} }
- (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint - (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
{ {
[self setObjectValue:[self _valueAtPoint:_CGPointMake(aPoint.x + _dragOffset.width, aPoint.y + _dragOffset.height)]]; [self setObjectValue:[self _valueAtPoint:_CGPointMake(aPoint.x + _dragOffset.width, aPoint.y + _dragOffset.height)]];
return YES; return YES;
} }
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp - (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
{ {
[self setHighlighted:NO]; [self setHighlighted:NO];
if ([_target respondsToSelector:@selector(sliderDidFinish:)]) if ([_target respondsToSelector:@selector(sliderDidFinish:)])
[_target sliderDidFinish:self]; [_target sliderDidFinish:self];
@@ -392,10 +390,22 @@ CPCircularSlider = 1;
{ {
if (flag) if (flag)
_sendActionOn |= CPLeftMouseDraggedMask; _sendActionOn |= CPLeftMouseDraggedMask;
else else
_sendActionOn &= ~CPLeftMouseDraggedMask; _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 @end
var CPSliderMinValueKey = "CPSliderMinValueKey", var CPSliderMinValueKey = "CPSliderMinValueKey",
@@ -442,14 +452,14 @@ var CPSliderMinValueKey = "CPSliderMinValueKey",
- (id)value - (id)value
{ {
CPLog.warn("[CPSlider value] is deprecated, use doubleValue or objectValue instead."); CPLog.warn("[CPSlider value] is deprecated, use doubleValue or objectValue instead.");
return [self doubleValue]; return [self doubleValue];
} }
- (void)setValue:(id)aValue - (void)setValue:(id)aValue
{ {
CPLog.warn("[CPSlider setValue:] is deprecated, use setDoubleValue: or setObjectValue: instead."); CPLog.warn("[CPSlider setValue:] is deprecated, use setDoubleValue: or setObjectValue: instead.");
[self setObjectValue:aValue]; [self setObjectValue:aValue];
} }
+103 -167
View File
@@ -20,8 +20,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CPView.j"
@import "CPColorPicker.j" @import "CPColorPicker.j"
/* /*
@ignore @ignore
*/ */
@@ -45,16 +47,15 @@
CPTextField _saturationLabel; CPTextField _saturationLabel;
CPTextField _brightnessLabel; CPTextField _brightnessLabel;
CPTextField _hexLabel; CPTextField _hexLabel;
CPTextField _hexValue;
#if PLATFORM(DOM) CPTextField _hexValue;
DOMElement _redValue; CPTextField _redValue;
DOMElement _greenValue; CPTextField _greenValue;
DOMElement _blueValue; CPTextField _blueValue;
DOMElement _hueValue; CPTextField _hueValue;
DOMElement _saturationValue; CPTextField _saturationValue;
DOMElement _brightnessValue; CPTextField _brightnessValue;
DOMElement _hexValue;
#endif
} }
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel - (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
@@ -84,73 +85,13 @@
[_redSlider setAction: @selector(sliderChanged:)]; [_redSlider setAction: @selector(sliderChanged:)];
[_redSlider setAutoresizingMask: CPViewWidthSizable]; [_redSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM) // red value input box
var updateFunction = function(aDOMEvent) _redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 29)];
{ [_redValue setAutoresizingMask: CPViewMinXMargin];
if(isNaN(this.value)) [_redValue setEditable: YES];
return; [_redValue setBezeled: YES];
[_redValue setDelegate: self];
switch(this) [_contentView addSubview: _redValue];
{
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
_greenLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 58, 15, 20)]; _greenLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 58, 15, 20)];
[_greenLabel setStringValue: "G"]; [_greenLabel setStringValue: "G"];
@@ -163,17 +104,13 @@
[_greenSlider setAction: @selector(sliderChanged:)]; [_greenSlider setAction: @selector(sliderChanged:)];
[_greenSlider setAutoresizingMask: CPViewWidthSizable]; [_greenSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM) // green value input box
//green value input box _greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 53, 45, 29)];
var greenValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 58, 45, 20)]; [_greenValue setAutoresizingMask: CPViewMinXMargin];
[greenValue setAutoresizingMask: CPViewMinXMargin]; [_greenValue setEditable: YES];
[_greenValue setBezeled: YES];
_greenValue = _redValue.cloneNode(false); [_greenValue setDelegate: self];
_greenValue.onchange = updateFunction; [_contentView addSubview: _greenValue];
greenValue._DOMElement.appendChild(_greenValue);
[_contentView addSubview: greenValue];
#endif
_blueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 81, 15, 20)]; _blueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 81, 15, 20)];
[_blueLabel setStringValue: "B"]; [_blueLabel setStringValue: "B"];
@@ -186,17 +123,14 @@
[_blueSlider setAction: @selector(sliderChanged:)]; [_blueSlider setAction: @selector(sliderChanged:)];
[_blueSlider setAutoresizingMask: CPViewWidthSizable]; [_blueSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM) // blue value input box
//blue value input box _blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 76, 45, 29)];
var blueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 81, 45, 20)]; [_blueValue setAutoresizingMask: CPViewMinXMargin];
[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 = [[CPTextField alloc] initWithFrame: CPRectMake(0, 120, 190, 20)];
[_hsbLabel setStringValue: "Hue, Saturation, Brightness"]; [_hsbLabel setStringValue: "Hue, Saturation, Brightness"];
[_hsbLabel setTextColor:[CPColor blackColor]]; [_hsbLabel setTextColor:[CPColor blackColor]];
@@ -212,17 +146,14 @@
[_hueSlider setAction: @selector(sliderChanged:)]; [_hueSlider setAction: @selector(sliderChanged:)];
[_hueSlider setAutoresizingMask: CPViewWidthSizable]; [_hueSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM) // hue value input box
//red value input box _hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 140, 45, 29)];
var hueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 145, 45, 20)]; [_hueValue setAutoresizingMask: CPViewMinXMargin];
[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 = [[CPTextField alloc] initWithFrame: CPRectMake(0, 168, 15, 20)];
[_saturationLabel setStringValue: "S"]; [_saturationLabel setStringValue: "S"];
[_saturationLabel setTextColor:[CPColor blackColor]]; [_saturationLabel setTextColor:[CPColor blackColor]];
@@ -234,17 +165,14 @@
[_saturationSlider setAction: @selector(sliderChanged:)]; [_saturationSlider setAction: @selector(sliderChanged:)];
[_saturationSlider setAutoresizingMask: CPViewWidthSizable]; [_saturationSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM) // saturation value input box
//green value input box _saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 163, 45, 29)];
var saturationValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 168, 45, 20)]; [_saturationValue setAutoresizingMask: CPViewMinXMargin];
[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 = [[CPTextField alloc] initWithFrame: CPRectMake(0, 191, 15, 20)];
[_brightnessLabel setStringValue: "B"]; [_brightnessLabel setStringValue: "B"];
[_brightnessLabel setTextColor:[CPColor blackColor]]; [_brightnessLabel setTextColor:[CPColor blackColor]];
@@ -256,51 +184,24 @@
[_brightnessSlider setAction: @selector(sliderChanged:)]; [_brightnessSlider setAction: @selector(sliderChanged:)];
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable]; [_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM) // brightness value input box
//blue value input box _brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 186, 45, 29)];
var brightnessValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 191, 45, 20)]; [_brightnessValue setAutoresizingMask: CPViewMinXMargin];
[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 = [[CPTextField alloc] initWithFrame: CPRectMake(0, 230, 30, 20)];
[_hexLabel setStringValue: "Hex"]; [_hexLabel setStringValue: "Hex"];
[_hexLabel setTextColor:[CPColor blackColor]]; [_hexLabel setTextColor:[CPColor blackColor]];
#if PLATFORM(DOM)
//hex input box //hex input box
_hexValue = _redValue.cloneNode(false); _hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 29)];
_hexValue.style.top = "228px"; [_hexValue setEditable: YES];
_hexValue.style.width = "80px"; [_hexValue setBezeled: YES];
_hexValue.style.left = "35px"; [_hexValue setDelegate: self];
_hexValue.onkeypress = function(aDOMEvent) [_contentView addSubview: _hexValue];
{
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
[_contentView addSubview: _rgbLabel]; [_contentView addSubview: _rgbLabel];
[_contentView addSubview: _redLabel]; [_contentView addSubview: _redLabel];
@@ -392,9 +293,7 @@
- (void)updateHex:(CPColor)aColor - (void)updateHex:(CPColor)aColor
{ {
#if PLATFORM(DOM) [_hexValue setStringValue:[aColor hexString]];
_hexValue.value = [aColor hexString];
#endif
} }
- (void)updateRGBSliders:(CPColor)aColor - (void)updateRGBSliders:(CPColor)aColor
@@ -408,15 +307,13 @@
- (void)updateLabels - (void)updateLabels
{ {
#if PLATFORM(DOM) [_hueValue setStringValue: ROUND([_hueSlider floatValue])];
_hueValue.value = ROUND([_hueSlider floatValue]); [_saturationValue setStringValue: ROUND([_saturationSlider floatValue])];
_saturationValue.value = ROUND([_saturationSlider floatValue]); [_brightnessValue setStringValue: ROUND([_brightnessSlider floatValue])];
_brightnessValue.value = ROUND([_brightnessSlider floatValue]);
_redValue.value = ROUND([_redSlider floatValue] * 255); [_redValue setStringValue: ROUND([_redSlider floatValue] * 255)];
_greenValue.value = ROUND([_greenSlider floatValue] * 255); [_greenValue setStringValue: ROUND([_greenSlider floatValue] * 255)];
_blueValue.value = ROUND([_blueSlider floatValue] * 255); [_blueValue setStringValue: ROUND([_blueSlider floatValue] * 255)];
#endif
} }
- (CPImage)provideNewButtonImage - (CPImage)provideNewButtonImage
@@ -429,4 +326,43 @@
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:CPColorPicker] pathForResource:"slider_button_h.png"] size:CGSizeMake(32, 32)]; 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 @end
+54 -32
View File
@@ -24,10 +24,6 @@
@import "CPImage.j" @import "CPImage.j"
@import "CPView.j" @import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
#include "Platform/Platform.h"
#include "Platform/DOM/CPDOMDisplayServer.h"
CPSplitViewDidResizeSubviewsNotification = @"CPSplitViewDidResizeSubviewsNotification"; CPSplitViewDidResizeSubviewsNotification = @"CPSplitViewDidResizeSubviewsNotification";
CPSplitViewWillResizeSubviewsNotification = @"CPSplitViewWillResizeSubviewsNotification"; CPSplitViewWillResizeSubviewsNotification = @"CPSplitViewWillResizeSubviewsNotification";
@@ -47,6 +43,7 @@ var CPSplitViewHorizontalImage = nil,
int _currentDivider; int _currentDivider;
float _initialOffset; float _initialOffset;
float _preCollapsePosition;
CPString _originComponent; CPString _originComponent;
CPString _sizeComponent; CPString _sizeComponent;
@@ -60,6 +57,17 @@ var CPSplitViewHorizontalImage = nil,
CPArray _buttonBars; 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"]];
}
/* /*
@ignore @ignore
*/ */
@@ -90,7 +98,7 @@ var CPSplitViewHorizontalImage = nil,
- (float)dividerThickness - (float)dividerThickness
{ {
return _isPaneSplitter ? 1.0 : 10.0; return [self currentValueForThemeAttribute:[self isPaneSplitter] ? @"pane-divider-thickness" : @"divider-thickness"];
} }
- (BOOL)isVertical - (BOOL)isVertical
@@ -151,8 +159,8 @@ var CPSplitViewHorizontalImage = nil,
_isPaneSplitter = shouldBePaneSplitter; _isPaneSplitter = shouldBePaneSplitter;
if(_DOMDividerElements[_drawingDivider]) if (_DOMDividerElements[_drawingDivider])
[self _setupDOMDivider] [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. // subviews need to change size too.
@@ -185,9 +193,8 @@ var CPSplitViewHorizontalImage = nil,
- (CGRect)effectiveRectOfDividerAtIndex:(int)aDivider - (CGRect)effectiveRectOfDividerAtIndex:(int)aDivider
{ {
var realRect = [self rectOfDividerAtIndex:aDivider]; var realRect = [self rectOfDividerAtIndex:aDivider],
padding = 2;
var padding = 2;
realRect.size[_sizeComponent] += padding * 2; realRect.size[_sizeComponent] += padding * 2;
realRect.origin[_originComponent] -= padding; realRect.origin[_originComponent] -= padding;
@@ -217,10 +224,9 @@ var CPSplitViewHorizontalImage = nil,
_DOMDividerElements[_drawingDivider].style.backgroundRepeat = "repeat"; _DOMDividerElements[_drawingDivider].style.backgroundRepeat = "repeat";
CPDOMDisplayServerAppendChild(_DOMElement, _DOMDividerElements[_drawingDivider]); CPDOMDisplayServerAppendChild(_DOMElement, _DOMDividerElements[_drawingDivider]);
[self _setupDOMDivider];
} }
[self _setupDOMDivider];
CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect)); CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect));
CPDOMDisplayServerSetStyleSize(_DOMDividerElements[_drawingDivider], _CGRectGetWidth(aRect), _CGRectGetHeight(aRect)); CPDOMDisplayServerSetStyleSize(_DOMDividerElements[_drawingDivider], _CGRectGetWidth(aRect), _CGRectGetHeight(aRect));
#endif #endif
@@ -230,7 +236,7 @@ var CPSplitViewHorizontalImage = nil,
{ {
if (_isPaneSplitter) if (_isPaneSplitter)
{ {
_DOMDividerElements[_drawingDivider].style.backgroundColor = "#A5A5A5"; _DOMDividerElements[_drawingDivider].style.backgroundColor = [[self currentValueForThemeAttribute:@"pane-divider-color"] cssString];
_DOMDividerElements[_drawingDivider].style.backgroundImage = ""; _DOMDividerElements[_drawingDivider].style.backgroundImage = "";
} }
else else
@@ -294,7 +300,7 @@ var CPSplitViewHorizontalImage = nil,
if ([_delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)]) if ([_delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)])
additionalRect = [_delegate splitView:self additionalEffectiveRectOfDividerAtIndex:anIndex]; additionalRect = [_delegate splitView:self additionalEffectiveRectOfDividerAtIndex:anIndex];
return CGRectContainsPoint(effectiveRect, aPoint) || return CGRectContainsPoint(effectiveRect, aPoint) ||
(additionalRect && CGRectContainsPoint(additionalRect, aPoint)) || (additionalRect && CGRectContainsPoint(additionalRect, aPoint)) ||
(buttonBarRect && CGRectContainsPoint(buttonBarRect, aPoint)); (buttonBarRect && CGRectContainsPoint(buttonBarRect, aPoint));
} }
@@ -304,9 +310,9 @@ var CPSplitViewHorizontalImage = nil,
if ([self isHidden] || ![self hitTests] || !CGRectContainsPoint([self frame], aPoint)) if ([self isHidden] || ![self hitTests] || !CGRectContainsPoint([self frame], aPoint))
return nil; 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++) for (var i = 0; i < count; i++)
{ {
if ([self cursorAtPoint:point hitDividerAtIndex:i]) if ([self cursorAtPoint:point hitDividerAtIndex:i])
@@ -359,14 +365,14 @@ var CPSplitViewHorizontalImage = nil,
if ([_delegate splitView:self canCollapseSubview:_subviews[i]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i] forDoubleClickOnDividerAtIndex:i]) if ([_delegate splitView:self canCollapseSubview:_subviews[i]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i] forDoubleClickOnDividerAtIndex:i])
{ {
if ([self isSubviewCollapsed:_subviews[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 else
[self setPosition:minPosition ofDividerAtIndex:i]; [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]]) if ([self isSubviewCollapsed:_subviews[i + 1]])
[self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i]; [self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
else else
[self setPosition:maxPosition ofDividerAtIndex:i]; [self setPosition:maxPosition ofDividerAtIndex:i];
} }
@@ -445,11 +451,19 @@ var CPSplitViewHorizontalImage = nil,
if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i])) if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i]))
{ {
var frame = [_subviews[i] frame], var frame = [_subviews[i] frame],
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent], size = frame.size[_sizeComponent],
canShrink = [self _realPositionForPosition:startPosition-1 ofDividerAtIndex:i] < startPosition, startPosition = frame.origin[_originComponent] + size,
canGrow = [self _realPositionForPosition:startPosition+1 ofDividerAtIndex:i] > startPosition, canShrink = [self _realPositionForPosition:startPosition - 1 ofDividerAtIndex:i] < startPosition,
canGrow = [self _realPositionForPosition:startPosition + 1 ofDividerAtIndex:i] > startPosition,
cursor = [CPCursor arrowCursor]; 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) if (_isVertical && canShrink && canGrow)
cursor = [CPCursor resizeLeftRightCursor]; cursor = [CPCursor resizeLeftRightCursor];
else if (_isVertical && canShrink) else if (_isVertical && canShrink)
@@ -504,10 +518,10 @@ var CPSplitViewHorizontalImage = nil,
actualMax = proposedMax, actualMax = proposedMax,
actualMin = proposedMin; actualMin = proposedMin;
if([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)]) if ([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)])
actualMin = [_delegate splitView:self constrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex]; 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]; actualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
var viewA = _subviews[dividerIndex], var viewA = _subviews[dividerIndex],
@@ -532,10 +546,18 @@ var CPSplitViewHorizontalImage = nil,
viewB = _subviews[dividerIndex + 1], viewB = _subviews[dividerIndex + 1],
frameB = [viewB frame]; frameB = [viewB frame];
_preCollapsePosition = 0;
var preSize = frameA.size[_sizeComponent];
frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent]; frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent];
if (preSize !== 0 && frameA.size[_sizeComponent] === 0)
_preCollapsePosition = preSize;
[_subviews[dividerIndex] setFrame:frameA]; [_subviews[dividerIndex] setFrame:frameA];
preSize = frameB.size[_sizeComponent];
frameB.size[_sizeComponent] = frameB.origin[_originComponent] + frameB.size[_sizeComponent] - realPosition - [self dividerThickness]; 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]; frameB.origin[_originComponent] = realPosition + [self dividerThickness];
[_subviews[dividerIndex + 1] setFrame:frameB]; [_subviews[dividerIndex + 1] setFrame:frameB];
@@ -590,8 +612,8 @@ var CPSplitViewHorizontalImage = nil,
var nonSizableSpace = totalSizableSpace ? bounds.size[_sizeComponent] - totalSizableSpace : 0, var nonSizableSpace = totalSizableSpace ? bounds.size[_sizeComponent] - totalSizableSpace : 0,
remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent], remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent],
oldDimension = (oldSize[_sizeComponent]- totalDividers*dividerThickness - nonSizableSpace), oldDimension = (oldSize[_sizeComponent] - totalDividers * dividerThickness - nonSizableSpace),
ratio = oldDimension <= 0 ? 0 : (bounds.size[_sizeComponent] - totalDividers*dividerThickness - nonSizableSpace) / oldDimension; ratio = oldDimension <= 0 ? 0 : (bounds.size[_sizeComponent] - totalDividers * dividerThickness - nonSizableSpace) / oldDimension;
for (index = 0; index < count; ++index) for (index = 0; index < count; ++index)
{ {
@@ -642,14 +664,14 @@ var CPSplitViewHorizontalImage = nil,
/*! /*!
Set the button bar who's resize control should act as a control for this splitview. 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 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. 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 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 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. should usually call this method after adding all the desired subviews to the split view.
This method will automatically configure the hasResizeControl and resizeControlIsLeftAligned This method will automatically configure the hasResizeControl and resizeControlIsLeftAligned
parameters of the button bar, and will override any currently set values. parameters of the button bar, and will override any currently set values.
*/ */
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex - (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex
@@ -670,7 +692,7 @@ var CPSplitViewHorizontalImage = nil,
} }
if (view !== self) if (view !== self)
[CPException raise:CPInvalidArgumentException [CPException raise:CPInvalidArgumentException
reason:@"CPSplitView button bar must be a subview of the split view."]; reason:@"CPSplitView button bar must be a subview of the split view."];
var viewIndex = [[self subviews] indexOfObject:subview]; var viewIndex = [[self subviews] indexOfObject:subview];
@@ -678,7 +700,7 @@ var CPSplitViewHorizontalImage = nil,
[aButtonBar setHasResizeControl:YES]; [aButtonBar setHasResizeControl:YES];
[aButtonBar setResizeControlIsLeftAligned:dividerIndex < viewIndex]; [aButtonBar setResizeControlIsLeftAligned:dividerIndex < viewIndex];
_buttonBars[dividerIndex] = aButtonBar; _buttonBars[dividerIndex] = aButtonBar;
} }
- (void)_postNotificationWillResize - (void)_postNotificationWillResize
@@ -715,7 +737,7 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
_DOMDividerElements = []; _DOMDividerElements = [];
_buttonBars = [aCoder decodeObjectForKey:CPSplitViewButtonBarsKey] || []; _buttonBars = [aCoder decodeObjectForKey:CPSplitViewButtonBarsKey] || [];
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey]; _delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];
_isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey]; _isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey];
+25 -1
View File
@@ -25,8 +25,20 @@
@import "CPPlatformString.j" @import "CPPlatformString.j"
var CPStringSizeWithFontInWidthCache = {};
CPStringSizeCachingEnabled = YES;
@implementation CPString (CPStringDrawing) @implementation CPString (CPStringDrawing)
/*!
Returns a dictionary with the items "ascender", "descender", "lineHeight"
*/
+ (CPDictionary)metricsOfFont:(CPFont)aFont
{
return [CPPlatformString metricsOfFont:aFont];
}
/*! /*!
Returns the string Returns the string
*/ */
@@ -42,7 +54,19 @@
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth - (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 @end
+202 -553
View File
@@ -1,32 +1,8 @@
/* @import "CPBox.j"
* CPTabView.j @import "CPSegmentedControl.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 "CPTabViewItem.j" @import "CPTabViewItem.j"
@import "CPView.j" @import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
/* /*
Places tabs on top with a bezeled border. Places tabs on top with a bezeled border.
@global @global
@@ -34,7 +10,7 @@
*/ */
CPTopTabsBezelBorder = 0; CPTopTabsBezelBorder = 0;
//CPLeftTabsBezelBorder = 1; //CPLeftTabsBezelBorder = 1;
//CPBottomTabsBezelBorder = 2; CPBottomTabsBezelBorder = 2;
//CPRightTabsBezelBorder = 3; //CPRightTabsBezelBorder = 3;
/* /*
Displays no tabs and has a bezeled border. Displays no tabs and has a bezeled border.
@@ -55,173 +31,55 @@ CPNoTabsLineBorder = 5;
*/ */
CPNoTabsNoBorder = 6; 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, var CPTabViewDidSelectTabViewItemSelector = 1,
CPTabViewShouldSelectTabViewItemSelector = 2, CPTabViewShouldSelectTabViewItemSelector = 2,
CPTabViewWillSelectTabViewItemSelector = 4, CPTabViewWillSelectTabViewItemSelector = 4,
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8; CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
/*! var HEIGHT_OF_SEGMENTED_CONTROL = 24;
@ingroup appkit
@class CPTabView
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 @implementation CPTabView : CPView
{ {
CPView _labelsView; CPArray items;
CPView _backgroundView;
CPView _separatorView;
CPView _auxiliaryView;
CPView _contentView;
CPArray _tabViewItems;
CPTabViewItem _selectedTabViewItem;
CPTabViewType _tabViewType; CPSegmentedControl tabs;
CPBox box;
id _delegate;
unsigned _delegateSelectors;
}
/* CPNumber selectedIndex;
@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,
bezelBorderLeftImage, CPTabViewType type;
backgroundImage,
bezelBorderRightImage,
bezelBorderLeftImage, id delegate;
bezerBorderImage, unsigned delegateSelectors;
bezelBorderRightImage
]]];
CPTabViewBezelBorderColor = [CPColor colorWithPatternImage:bezerBorderImage];
}
/*
@ignore
*/
+ (CPColor)bezelBorderColor
{
return CPTabViewBezelBorderColor;
} }
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
_tabViewType = CPTopTabsBezelBorder; items = [CPArray array];
_tabViewItems = [];
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; 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 // Adding and Removing Tabs
/*! /*!
Adds a CPTabViewItem to the tab view. Adds a CPTabViewItem to the tab view.
@@ -229,7 +87,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/ */
- (void)addTabViewItem:(CPTabViewItem)aTabViewItem - (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 - (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(unsigned)anIndex
{ {
if (!_labelsView && _tabViewType == CPTopTabsBezelBorder) [items insertObject:aTabViewItem atIndex:anIndex];
[self _createBezelBorder];
[_tabViewItems insertObject:aTabViewItem atIndex:anIndex];
[_labelsView tabView:self didAddTabViewItem:aTabViewItem];
[aTabViewItem _setTabView:self];
if ([_tabViewItems count] == 1)
[self selectFirstTabViewItem:self];
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector) [self _updateItems];
[_delegate tabViewDidChangeNumberOfTabViewItems:self]; [self _repositionTabs];
if (delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[delegate tabViewDidChangeNumberOfTabViewItems:self];
} }
/*! /*!
@@ -262,16 +113,19 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/ */
- (void)removeTabViewItem:(CPTabViewItem)aTabViewItem - (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]; [self _updateItems];
[self _repositionTabs];
[_labelsView tabView:self didRemoveTabViewItemAtIndex:index];
if (delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[aTabViewItem _setTabView:nil]; [delegate tabViewDidChangeNumberOfTabViewItems:self];
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
} }
// Accessing Tabs // Accessing Tabs
@@ -281,7 +135,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/ */
- (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem - (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem
{ {
return [_tabViewItems indexOfObjectIdenticalTo:aTabViewItem]; return [items indexOfObjectIdenticalTo:aTabViewItem];
} }
/*! /*!
@@ -290,14 +144,11 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/ */
- (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier - (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier
{ {
var index = 0, for (var index = [items count]; index >= 0; index--)
count = [_tabViewItems count]; if ([[items[index] identifier] isEqual:anIdentifier])
for (; index < count; ++index)
if ([[_tabViewItems[index] identifier] isEqual:anIdentifier])
return index; return index;
return index; return CPNotFound;
} }
/*! /*!
@@ -305,7 +156,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/ */
- (unsigned)numberOfTabViewItems - (unsigned)numberOfTabViewItems
{ {
return [_tabViewItems count]; return [items count];
} }
/*! /*!
@@ -313,7 +164,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/ */
- (CPTabViewItem)tabViewItemAtIndex:(unsigned)anIndex - (CPTabViewItem)tabViewItemAtIndex:(unsigned)anIndex
{ {
return _tabViewItems[anIndex]; return [items objectAtIndex:anIndex];
} }
/*! /*!
@@ -321,7 +172,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/ */
- (CPArray)tabViewItems - (CPArray)tabViewItems
{ {
return _tabViewItems; return [items copy]; // Copy?
} }
// Selecting a Tab // Selecting a Tab
@@ -331,10 +182,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/ */
- (void)selectFirstTabViewItem:(id)aSender - (void)selectFirstTabViewItem:(id)aSender
{ {
var count = [_tabViewItems count]; if ([items count] === 0)
return; // throw?
if (count)
[self selectTabViewItemAtIndex:0]; [self selectTabViewItemAtIndex:0];
} }
/*! /*!
@@ -343,10 +194,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/ */
- (void)selectLastTabViewItem:(id)aSender - (void)selectLastTabViewItem:(id)aSender
{ {
var count = [_tabViewItems count]; if ([items count] === 0)
return; // throw?
if (count)
[self selectTabViewItemAtIndex:count - 1]; [self selectTabViewItemAtIndex:[items count] - 1];
} }
/*! /*!
@@ -355,13 +206,16 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/ */
- (void)selectNextTabViewItem:(id)aSender - (void)selectNextTabViewItem:(id)aSender
{ {
if (!_selectedTabViewItem) if (selectedIndex === CPNotFound)
return; return;
var index = [self indexOfTabViewItem:_selectedTabViewItem], var nextIndex = selectedIndex + 1;
count = [_tabViewItems count];
if (nextIndex === [items count])
[self selectTabViewItemAtIndex:index + 1 % 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 - (void)selectPreviousTabViewItem:(id)aSender
{ {
if (!_selectedTabViewItem) if (selectedIndex === CPNotFound)
return; return;
var index = [self indexOfTabViewItem:_selectedTabViewItem], var previousIndex = selectedIndex - 1;
count = [_tabViewItems count];
if (previousIndex < 0)
[self selectTabViewItemAtIndex:index == 0 ? count : index - 1]; return; // does nothing. See above.
[self selectTabViewItemAtIndex:previousIndex];
} }
/*! /*!
@@ -385,41 +241,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/ */
- (void)selectTabViewItem:(CPTabViewItem)aTabViewItem - (void)selectTabViewItem:(CPTabViewItem)aTabViewItem
{ {
if ((_delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![_delegate tabView:self shouldSelectTabViewItem:aTabViewItem]) [self selectTabViewItemAtIndex:[self indexOfTabViewItem: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];
} }
/*! /*!
@@ -428,7 +250,24 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/ */
- (void)selectTabViewItemAtIndex:(unsigned)anIndex - (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 - (CPTabViewItem)selectedTabViewItem
{ {
return _selectedTabViewItem; return [items objectAtIndex:selectedIndex];
} }
// //
/*! /*!
Sets the tab view type. Sets the tab view type.
@param aTabViewType the view type @param aTabViewType the view type
*/ */
- (void)setTabViewType:(CPTabViewType)aTabViewType - (void)setTabViewType:(CPTabViewType)aTabViewType
{ {
if (_tabViewType == aTabViewType) if (type === aTabViewType)
return; return;
_tabViewType = aTabViewType; if ((type === CPTopTabsBezelBorder || type === CPBottomTabsBezelBorder)
&& (aTabViewType !== CPTopTabsBezelBorder && aTabViewType !== CPBottomTabsBezelBorder))
if (_tabViewType == CPNoTabsBezelBorder || _tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder) [tabs removeFromSuperview];
[_labelsView removeFromSuperview];
else if (![_labelsView superview]) if ((type === CPNoTabsBezelBorder || type === CPNoTabsLineBorder || type === CPNoTabsNoBorder)
[self addSubview:_labelsView]; && (aTabViewType !== CPNoTabsBezelBorder && aTabViewType !== CPNoTabsBezelBorder && aTabViewType !== CPNoTabsNoBorder))
[self addSubview:tabs];
if (_tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder)
[_backgroundView removeFromSuperview]; type = aTabViewType;
else if (![_backgroundView superview])
[self addSubview:_backgroundView]; switch (type)
{
[self layoutSubviews]; 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 - (CPTabViewType)tabViewType
{ {
return _tabViewType; return type;
}
// 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;
} }
/*! /*!
@@ -501,7 +327,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/ */
- (id)delegate - (id)delegate
{ {
return _delegate; return delegate;
} }
/*! /*!
@@ -510,35 +336,74 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/ */
- (void)setDelegate:(id)aDelegate - (void)setDelegate:(id)aDelegate
{ {
if (_delegate == aDelegate) if (delegate == aDelegate)
return; return;
_delegate = aDelegate;
_delegateSelectors = 0;
if ([_delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)]) delegate = aDelegate;
_delegateSelectors |= CPTabViewShouldSelectTabViewItemSelector;
if ([_delegate respondsToSelector:@selector(tabView:willSelectTabViewItem:)]) delegateSelectors = 0;
_delegateSelectors |= CPTabViewWillSelectTabViewItemSelector;
if ([_delegate respondsToSelector:@selector(tabView:didSelectTabViewItem:)]) if ([delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)])
_delegateSelectors |= CPTabViewDidSelectTabViewItemSelector; delegateSelectors |= CPTabViewShouldSelectTabViewItemSelector;
if ([_delegate respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)]) if ([delegate respondsToSelector:@selector(tabView:willSelectTabViewItem:)])
_delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector; 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 - (void)mouseDown:(CPEvent)anEvent
{ {
var location = [_labelsView convertPoint:[anEvent locationInWindow] fromView:nil], var segmentIndex = [tabs testSegment:[tabs convertPoint:[anEvent locationInWindow] fromView:nil]];
tabViewItem = [_labelsView representedTabViewItemAtPoint:location];
if (segmentIndex != CPNotFound)
if (tabViewItem) {
[self selectTabViewItem:tabViewItem]; [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 @end
@@ -554,20 +419,17 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
{ {
if (self = [super initWithCoder:aCoder]) if (self = [super initWithCoder:aCoder])
{ {
_tabViewType = [aCoder decodeIntForKey:CPTabViewTypeKey]; type = [aCoder decodeIntForKey:CPTabViewTypeKey];
_tabViewItems = []; items = [];
// FIXME: this is somewhat hacky var encodedItems = [aCoder decodeObjectForKey:CPTabViewItemsKey];
[self _createBezelBorder]; for (var i = 0; encodedItems && i < encodedItems.length; i++)
[self insertTabViewItem:encodedItems[i] atIndex:i];
var items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
for (var i = 0; items && i < items.length; i++)
[self insertTabViewItem:items[i] atIndex:i];
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey]; var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
if (selected) if (selected)
[self selectTabViewItem:selected]; [self selectTabViewItem:selected];
[self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]]; [self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
} }
@@ -576,227 +438,14 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
var actualSubviews = _subviews;
_subviews = [];
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
_subviews = actualSubviews;
[aCoder encodeObject:items forKey:CPTabViewItemsKey];;
[aCoder encodeObject:_tabViewItems forKey:CPTabViewItemsKey];; [aCoder encodeObject:[self selectedTabViewItem] forKey:CPTabViewSelectedItemKey];
[aCoder encodeObject:_selectedTabViewItem forKey:CPTabViewSelectedItemKey];
[aCoder encodeInt:type forKey:CPTabViewTypeKey];
[aCoder encodeInt:_tabViewType forKey:CPTabViewTypeKey];
[aCoder encodeConditionalObject:delegate forKey:CPTabViewDelegateKey];
[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]];
} }
@end @end
+1 -1
View File
@@ -22,7 +22,7 @@
@import <Foundation/CPObject.j> @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/CPDictionary.j>
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import <Foundation/CPIndexSet.j>
@import <Foundation/CPSortDescriptor.j> @import <Foundation/CPSortDescriptor.j>
@import <Foundation/CPString.j> @import <Foundation/CPString.j>
@import "CPTableHeaderView.j" @import "CPTableHeaderView.j"
#include "CoreGraphics/CGGeometry.h"
CPTableColumnNoResizing = 0; CPTableColumnNoResizing = 0;
CPTableColumnAutoresizingMask = 1 << 0; CPTableColumnAutoresizingMask = 1 << 0;
@@ -50,7 +50,7 @@ CPTableColumnUserResizingMask = 1 << 1;
CPSortDescriptor _sortDescriptorPrototype; CPSortDescriptor _sortDescriptorPrototype;
BOOL _isHidden; BOOL _isHidden;
CPString _headerToolTip; CPString _headerToolTip;
BOOL _disableResizingPosting @accessors(property=disableResizingPosting); BOOL _disableResizingPosting @accessors(property=disableResizingPosting);
} }
@@ -72,19 +72,13 @@ CPTableColumnUserResizingMask = 1 << 1;
_maxWidth = 1000000.0; _maxWidth = 1000000.0;
_resizingMask = CPTableColumnAutoresizingMask | CPTableColumnUserResizingMask; _resizingMask = CPTableColumnAutoresizingMask | CPTableColumnUserResizingMask;
_disableResizingPosting = NO; _disableResizingPosting = NO;
[self setIdentifier:anIdentifier]; [self setIdentifier:anIdentifier];
var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()]; var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()];
[self setHeaderView:header]; [self setHeaderView:header];
var textDataView = [CPTextField new]; [self setDataView:[CPTextField new]];
[textDataView setLineBreakMode:CPLineBreakByTruncatingTail];
[textDataView setValue:[CPColor colorWithHexString:@"333333"] forThemeAttribute:@"text-color"];
[textDataView setValue:[CPColor whiteColor] forThemeAttribute:@"text-color" inState:CPThemeStateSelected];
[textDataView setValue:[CPFont boldSystemFontOfSize:12] forThemeAttribute:@"font" inState:CPThemeStateSelected];
[textDataView setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
[self setDataView:textDataView];
} }
return self; return self;
@@ -123,19 +117,19 @@ CPTableColumnUserResizingMask = 1 << 1;
{ {
var index = [[tableView tableColumns] indexOfObjectIdenticalTo:self], var index = [[tableView tableColumns] indexOfObjectIdenticalTo:self],
dirtyTableColumnRangeIndex = tableView._dirtyTableColumnRangeIndex; dirtyTableColumnRangeIndex = tableView._dirtyTableColumnRangeIndex;
if (dirtyTableColumnRangeIndex < 0) if (dirtyTableColumnRangeIndex < 0)
tableView._dirtyTableColumnRangeIndex = index; tableView._dirtyTableColumnRangeIndex = index;
else else
tableView._dirtyTableColumnRangeIndex = MIN(index, tableView._dirtyTableColumnRangeIndex); tableView._dirtyTableColumnRangeIndex = MIN(index, tableView._dirtyTableColumnRangeIndex);
var rows = tableView._exposedRows, 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. // 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 _layoutDataViewsInRows:rows columns:columns];
[tableView tile]; [tableView tile];
if (!_disableResizingPosting) if (!_disableResizingPosting)
[self _postDidResizeNotificationWithOldWidth:oldWidth]; [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. 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. individual cell that is shown. As a result, changes made after calling this method won't be reflected.
Example: Example:
[tableColumn setDataView:someView]; // snapshot taken [tableColumn setDataView:someView]; // snapshot taken
[[tableColumn dataView] setSomething:x]; //won't work [[tableColumn dataView] setSomething:x]; //won't work
@@ -248,12 +242,11 @@ CPTableColumnUserResizingMask = 1 << 1;
*/ */
- (void)setDataView:(CPView)aView - (void)setDataView:(CPView)aView
{ {
if (_dataView === aView)
return;
if (_dataView) if (_dataView)
_dataViewData[[_dataView UID]] = nil; _dataViewData[[_dataView UID]] = nil;
[aView setThemeState:CPThemeStateTableDataView];
_dataView = aView; _dataView = aView;
_dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView]; _dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView];
} }
@@ -292,7 +285,10 @@ CPTableColumnUserResizingMask = 1 << 1;
// unarchive the data view cache // unarchive the data view cache
var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]]; var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]];
newDataView.identifier = dataViewUID; newDataView.identifier = dataViewUID;
// make sure only we have control over the size and placement
[newDataView setAutoresizingMask:CPViewNotSizable];
return newDataView; 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. column in the NSTableView, NO otherwise.
*/ */
- (BOOL)isEditable - (BOOL)isEditable
@@ -348,7 +344,14 @@ CPTableColumnUserResizingMask = 1 << 1;
- (void)setHidden:(BOOL)shouldBeHidden - (void)setHidden:(BOOL)shouldBeHidden
{ {
shouldBeHidden = !!shouldBeHidden
if (_isHidden === shouldBeHidden)
return;
_isHidden = shouldBeHidden; _isHidden = shouldBeHidden;
[[self headerView] setHidden:shouldBeHidden];
[[self tableView] _tableColumnVisibilityDidChange:self];
} }
- (BOOL)isHidden - (BOOL)isHidden
@@ -359,7 +362,7 @@ CPTableColumnUserResizingMask = 1 << 1;
//Setting Tool Tips //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. header cell of the receiver.
*/ */
- (void)setHeaderToolTip:(CPString)aToolTip - (void)setHeaderToolTip:(CPString)aToolTip
@@ -382,13 +385,86 @@ CPTableColumnUserResizingMask = 1 << 1;
@end @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", var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
CPTableColumnHeaderViewKey = @"CPTableColumnHeaderViewKey", CPTableColumnHeaderViewKey = @"CPTableColumnHeaderViewKey",
CPTableColumnDataViewKey = @"CPTableColumnDataViewKey", CPTableColumnDataViewKey = @"CPTableColumnDataViewKey",
CPTableColumnWidthKey = @"CPTableColumnWidthKey", CPTableColumnWidthKey = @"CPTableColumnWidthKey",
CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey", CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey",
CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey", CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey",
CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey"; CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey",
CPTableColumnIsHiddenKey = @"CPTableColumnIsHiddenKey",
CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey",
CPTableColumnIsEditableKey = @"CPTableColumnIsEditableKey";
@implementation CPTableColumn (CPCoding) @implementation CPTableColumn (CPCoding)
@@ -409,7 +485,11 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]]; [self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]]; [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; return self;
@@ -427,6 +507,10 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey]; [aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey]; [aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
[aCoder encodeBool:_isHidden forKey:CPTableColumnIsHiddenKey];
[aCoder encodeBool:_isEditable forKey:CPTableColumnIsEditableKey];
[aCoder encodeObject:_sortDescriptorPrototype forKey:CPSortDescriptorPrototypeKey];
} }
@end @end
@@ -463,4 +547,4 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
reason:@"dataCellForRow: is not supported. Use -dataViewForRow:row instead."]; reason:@"dataCellForRow: is not supported. Use -dataViewForRow:row instead."];
} }
@end @end
+379 -193
View File
@@ -20,54 +20,64 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import <Foundation/CPIndexSet.j>
@import "CPTableColumn.j" @import "CPTableColumn.j"
@import "CPTableView.j" @import "CPTableView.j"
@import "CPView.j" @import "CPView.j"
@implementation _CPTableColumnHeaderView : CPView @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 - (void)initWithFrame:(CGRect)frame
{ {
self = [super initWithFrame:frame]; self = [super initWithFrame:frame];
if (self) if (self)
{
[self _init]; [self _init];
}
return self; return self;
} }
- (void)_init - (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 setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_textField setLineBreakMode:CPLineBreakByTruncatingTail]; [_textField setLineBreakMode:CPLineBreakByTruncatingTail];
[_textField setTextColor: [CPColor colorWithHexString: @"333333"]];
[_textField setFont:[CPFont boldSystemFontOfSize:12.0]];
[_textField setAlignment:CPLeftTextAlignment]; [_textField setAlignment:CPLeftTextAlignment];
[_textField setVerticalAlignment:CPCenterVerticalTextAlignment]; [_textField setVerticalAlignment:CPCenterVerticalTextAlignment];
[_textField setTextShadowColor:[CPColor whiteColor]];
[_textField setTextShadowOffset:CGSizeMake(0,1)];
[self addSubview:_textField]; [self addSubview:_textField];
} }
- (void)layoutSubviews - (void)layoutSubviews
{ {
var themeState = [self themeState]; [self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
if(themeState & CPThemeStateSelected && themeState & CPThemeStateHighlighted) var inset = [self currentValueForThemeAttribute:@"text-inset"],
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted-pressed.png", CGSizeMake(1.0, 22.0))]]; bounds = [self bounds];
else if (themeState & CPThemeStateSelected)
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted.png", CGSizeMake(1.0, 22.0))]]; [_textField setFrame:_CGRectMake(inset.right, inset.top, bounds.size.width - inset.right - inset.left, bounds.size.height - inset.top - inset.bottom)];
else if (themeState & CPThemeStateHighlighted) [_textField setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-pressed.png", CGSizeMake(1.0, 22.0))]]; [_textField setFont:[self currentValueForThemeAttribute:@"text-font"]];
else [_textField setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]];
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]]; [_textField setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
[_textField setAlignment:[self currentValueForThemeAttribute:@"text-alignment"]];
} }
- (void)setStringValue:(CPString)string - (void)setStringValue:(CPString)string
@@ -95,11 +105,6 @@
[_textField setFont:aFont]; [_textField setFont:aFont];
} }
- (void)setValue:(id)aValue forThemeAttribute:(id)aKey
{
[_textField setValue:aValue forThemeAttribute:aKey];
}
- (void)_setIndicatorImage:(CPImage)anImage - (void)_setIndicatorImage:(CPImage)anImage
{ {
if (anImage) if (anImage)
@@ -137,7 +142,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeObject:[_textField text] forKey:_CPTableColumnHeaderViewStringValueKey]; [aCoder encodeObject:[_textField text] forKey:_CPTableColumnHeaderViewStringValueKey];
[aCoder encodeObject:[_textField image] forKey:_CPTableColumnHeaderViewImageKey]; [aCoder encodeObject:[_textField image] forKey:_CPTableColumnHeaderViewImageKey];
[aCoder encodeObject:[_textField font] forKey:_CPTableColumnHeaderViewFontKey]; [aCoder encodeObject:[_textField font] forKey:_CPTableColumnHeaderViewFontKey];
@@ -147,27 +152,47 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
@implementation CPTableHeaderView : CPView @implementation CPTableHeaderView : CPView
{ {
int _resizedColumn @accessors(readonly, property=resizedColumn); CGPoint _mouseDownLocation;
int _draggedColumn @accessors(readonly, property=draggedColumn); CGPoint _previousTrackingLocation;
int _pressedColumn @accessors(readonly, property=pressedColumn); int _activeColumn;
int _pressedColumn;
float _draggedDistance @accessors(readonly, property=draggedDistance);
float _lastLocation; BOOL _isResizing;
float _columnOldWidth; BOOL _isDragging;
BOOL _isTrackingColumn;
CPTableView _tableView @accessors(property=tableView); 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 - (void)_init
{ {
_resizedColumn = -1; _mouseDownLocation = _CGPointMakeZero();
_draggedColumn = -1; _previousTrackingLocation = _CGPointMakeZero();
_activeColumn = -1;
_pressedColumn = -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 - (id)initWithFrame:(CGRect)aFrame
@@ -182,39 +207,41 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
- (int)columnAtPoint:(CGPoint)aPoint - (int)columnAtPoint:(CGPoint)aPoint
{ {
return [_tableView columnAtPoint:CGPointMake(aPoint.x, 0)]; return [_tableView columnAtPoint:CGPointMake(aPoint.x, aPoint.y)];
} }
- (CGRect)headerRectOfColumn:(int)aColumnIndex - (CGRect)headerRectOfColumn:(int)aColumnIndex
{ {
var tableColumns = [_tableView tableColumns]; var headerRect = [self bounds],
columnRect = [_tableView rectOfColumn:aColumnIndex];
if (aColumnIndex < 0 || aColumnIndex > [tableColumns count]) headerRect.origin.x = _CGRectGetMinX(columnRect);
[CPException raise:"invalid" reason:"tried to get headerRectOfColumn: on invalid column"]; headerRect.size.width = _CGRectGetWidth(columnRect);
// UPDATE COLUMN RANGES ? return headerRect;
}
var tableRange = _tableView._tableColumnRanges[aColumnIndex],
bounds = [self bounds];
var rMinX = ROUND(tableRange.location); - (void)setDrawsColumnLines:(BOOL)aFlag
bounds.origin.x = rMinX; {
bounds.size.width = FLOOR(tableRange.length + tableRange.location - rMinX); _drawsColumnLines = aFlag;
}
return bounds;
- (BOOL)drawsColumnLines
{
return _drawsColumnLines;
} }
- (CGRect)_cursorRectForColumn:(int)column - (CGRect)_cursorRectForColumn:(int)column
{ {
if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask)) if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask))
return CGRectMakeZero(); return _CGRectMakeZero();
var rect = [self headerRectOfColumn:column]; var rect = [self headerRectOfColumn:column];
rect.origin.x = CGRectGetMaxX(rect) - 5; rect.origin.x = _CGRectGetMaxX(rect) - 5;
rect.size.width = 20; rect.size.width = 20;
return rect; return rect;
} }
- (void)_setPressedColumn:(CPInteger)column - (void)_setPressedColumn:(CPInteger)column
@@ -223,117 +250,293 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
{ {
var headerView = [_tableView._tableColumns[_pressedColumn] headerView]; var headerView = [_tableView._tableColumns[_pressedColumn] headerView];
[headerView unsetThemeState:CPThemeStateHighlighted]; [headerView unsetThemeState:CPThemeStateHighlighted];
} }
if (column != -1) if (column != -1)
{ {
var headerView = [_tableView._tableColumns[column] headerView]; var headerView = [_tableView._tableColumns[column] headerView];
[headerView setThemeState:CPThemeStateHighlighted]; [headerView setThemeState:CPThemeStateHighlighted];
} }
_pressedColumn = column; _pressedColumn = column;
} }
- (void)mouseDown:(CPEvent)theEvent - (void)mouseDown:(CPEvent)theEvent
{ {
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil], [self trackMouse:theEvent];
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];
}
} }
- (void)trackMouseWithEvent:(CPEvent)theEvent - (void)trackMouse:(CPEvent)theEvent
{ {
var type = [theEvent type]; var type = [theEvent type],
currentLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil];
if (type == CPLeftMouseUp)
{
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
clickedColumn = [self columnAtPoint:location];
[self _setPressedColumn:-1]; // Take the right columns resize tracking area into account
currentLocation.x -= 5.0;
if (clickedColumn != -1)
[_tableView _didClickTableColumn:clickedColumn modifierFlags:[theEvent modifierFlags]];
return;
}
[CPApp setTarget:self selector:@selector(trackMouseWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPLeftMouseDownMask untilDate:nil inMode:nil dequeue:YES]; var columnIndex = [self columnAtPoint:currentLocation],
} shouldResize = [self shouldResizeTableColumn:columnIndex at:_CGPointMake(currentLocation.x + 5.0, currentLocation.y)];
- (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];
if (type === CPLeftMouseUp) 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 (shouldResize)
[self stopResizingTableColumn:_activeColumn at:currentLocation];
if (newWidth < [tableColumn minWidth]) else if ([self _shouldStopTrackingTableColumn:columnIndex at:currentLocation])
[[CPCursor resizeRightCursor] set]; {
else if (newWidth > [tableColumn maxWidth]) [_tableView _didClickTableColumn:columnIndex modifierFlags:[theEvent modifierFlags]];
[[CPCursor resizeLeftCursor] set]; [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 else
{ {
_tableView._lastColumnShouldSnap = NO; [self startTrackingTableColumn:columnIndex at:currentLocation];
[tableColumn setWidth:newWidth]; _isTrackingColumn = YES;
// 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. else if (type === CPLeftMouseDragged)
_lastLocation = location; {
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]; } else if (_isTrackingColumn && _pressedColumn !== -1)
[self setNeedsLayout]; [self stopTrackingTableColumn:_activeColumn at:currentLocation];
[self setNeedsDisplay:YES];
} }
} }
[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 - (void)_updateResizeCursor:(CPEvent)theEvent
@@ -345,15 +548,15 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
return; return;
} }
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil], var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
mouseOverLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y), mouseOverLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
overColumn = [self columnAtPoint:mouseOverLocation]; 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], var tableColumn = [[_tableView tableColumns] objectAtIndex:overColumn],
width = [tableColumn width]; width = [tableColumn width];
if (width == [tableColumn minWidth]) if (width == [tableColumn minWidth])
[[CPCursor resizeRightCursor] set]; [[CPCursor resizeRightCursor] set];
else if (width == [tableColumn maxWidth]) else if (width == [tableColumn maxWidth])
@@ -365,14 +568,8 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
[[CPCursor arrowCursor] set]; [[CPCursor arrowCursor] set];
} }
- (void)viewDidMoveToWindow
{
//if ([_tableView allowsColumnResizing])
// [[self window] setAcceptsMouseMovedEvents:YES];
}
- (void)mouseEntered:(CPEvent)theEvent - (void)mouseEntered:(CPEvent)theEvent
{ {
[self _updateResizeCursor:theEvent]; [self _updateResizeCursor:theEvent];
} }
@@ -390,31 +587,33 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
- (void)layoutSubviews - (void)layoutSubviews
{ {
var tableColumns = [_tableView tableColumns], var tableColumns = [_tableView tableColumns],
count = [tableColumns count]; count = [tableColumns count];
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
var column = [tableColumns objectAtIndex:i], var column = [tableColumns objectAtIndex:i],
headerView = [column headerView]; headerView = [column headerView];
var frame = [self headerRectOfColumn:i]; var frame = [self headerRectOfColumn:i];
frame.size.height -= 0.5; frame.size.height -= 0.5;
if (i > 0) if (i > 0)
{ {
frame.origin.x += 0.5; frame.origin.x += 0.5;
frame.size.width -= 1; frame.size.width -= 1;
} }
[headerView setFrame:frame]; [headerView setFrame:frame];
if([headerView superview] != self) if([headerView superview] != self)
[self addSubview:headerView]; [self addSubview:headerView];
} }
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
} }
- (void)drawRect:(CGRect)aRect - (void)drawRect:(CGRect)aRect
{ {
if (!_tableView) if (!_tableView || ![self drawsColumnLines])
return; return;
var context = [[CPGraphicsContext currentContext] graphicsPort], var context = [[CPGraphicsContext currentContext] graphicsPort],
@@ -426,55 +625,41 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1); exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1);
CGContextSetLineWidth(context, 1); CGContextSetLineWidth(context, 1);
CGContextSetStrokeColor(context, [_tableView gridColor]); CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"divider-color"]);
[exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange]; [exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange];
var columnArrayIndex = 0, var columnArrayIndex = 0,
columnArrayCount = columnsArray.length, columnArrayCount = columnsArray.length,
columnMaxX; columnMaxX;
CGContextBeginPath(context); CGContextBeginPath(context);
for(; columnArrayIndex < columnArrayCount; columnArrayIndex++) for(; columnArrayIndex < columnArrayCount; columnArrayIndex++)
{ {
// grab each column rect and add vertical lines // grab each column rect and add vertical lines
var columnIndex = columnsArray[columnArrayIndex], var columnIndex = columnsArray[columnArrayIndex],
columnToStroke = [self headerRectOfColumn:columnIndex]; columnToStroke = [self headerRectOfColumn:columnIndex];
columnMaxX = CGRectGetMaxX(columnToStroke); columnMaxX = _CGRectGetMaxX(columnToStroke);
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMinY(columnToStroke))); CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMaxY(columnToStroke))); CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMaxY(columnToStroke)));
} }
CGContextClosePath(context); CGContextClosePath(context);
CGContextStrokePath(context); CGContextStrokePath(context);
/* /*if (_isDragging)
var maxY = CGRectGetMaxY([self bounds]);
// draw normal gradient for remaining space
if (supportsCanvasGradient)
{ {
aRect.origin.x = columnMaxX - 0.5; CGContextSetFillColor(context, [CPColor grayColor]);
aRect.size.width -= columnMaxX; CGContextFillRect(context, [self headerRectOfColumn:_activeColumn])
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);
*/
} }
@end @end
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey"; var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey",
CPTableHeaderViewDrawsColumnLines = @"CPTableHeaderViewDrawsColumnLines";
@implementation CPTableHeaderView (CPCoding) @implementation CPTableHeaderView (CPCoding)
@@ -484,6 +669,7 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
{ {
[self _init]; [self _init];
_tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey]; _tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey];
_drawsColumnLines = [aCoder decodeBoolForKey:CPTableHeaderViewDrawsColumnLines];
} }
return self; return self;
@@ -493,7 +679,7 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey]; [aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey];
[aCoder encodeBool:_drawsColumnLines forKey:CPTableHeaderViewDrawsColumnLines];
} }
@end @end
+1040 -527
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";
+266 -119
View File
@@ -26,9 +26,6 @@
@import "CPCompatibility.j" @import "CPCompatibility.j"
@import "_CPImageAndTextView.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. */ CPTextFieldSquareBezel = 0; /*! A textfield bezel with a squared corners. */
CPTextFieldRoundedBezel = 1; /*! A textfield bezel with rounded corners. */ CPTextFieldRoundedBezel = 1; /*! A textfield bezel with rounded corners. */
@@ -49,7 +46,7 @@ var CPTextFieldDOMInputElement = nil,
CPTextFieldCachedSelectStartFunction = nil, CPTextFieldCachedSelectStartFunction = nil,
CPTextFieldCachedDragFunction = nil, CPTextFieldCachedDragFunction = nil,
CPTextFieldBlurFunction = nil; CPTextFieldBlurFunction = nil;
#endif #endif
var CPSecureTextFieldCharacter = "\u2022"; var CPSecureTextFieldCharacter = "\u2022";
@@ -80,15 +77,18 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
BOOL _isEditable; BOOL _isEditable;
BOOL _isSelectable; BOOL _isSelectable;
BOOL _isSecure; BOOL _isSecure;
BOOL _willBecomeFirstResponderByClick;
BOOL _drawsBackground; BOOL _drawsBackground;
CPColor _textFieldBackgroundColor; CPColor _textFieldBackgroundColor;
id _placeholderString; id _placeholderString;
id _originalPlaceholderString;
BOOL _currentValueIsPlaceholder;
id _delegate; id _delegate;
CPString _textDidChangeValue; CPString _textDidChangeValue;
// NS-style Display Properties // NS-style Display Properties
@@ -155,7 +155,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return textField; return textField;
} }
+ (CPString)themeClass + (CPString)defaultThemeClass
{ {
return "textfield"; return "textfield";
} }
@@ -199,7 +199,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
} }
CPTextFieldHandleBlur = function(anEvent) CPTextFieldHandleBlur = function(anEvent)
{ {
CPTextFieldInputOwner = nil; CPTextFieldInputOwner = nil;
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
@@ -207,10 +207,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
//FIXME make this not onblur //FIXME make this not onblur
CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction; CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction;
CPTextFieldDOMStandardInputElement = CPTextFieldDOMInputElement; CPTextFieldDOMStandardInputElement = CPTextFieldDOMInputElement;
} }
if (CPFeatureIsCompatible(CPInputTypeCanBeChangedFeature)) if (CPFeatureIsCompatible(CPInputTypeCanBeChangedFeature))
{ {
if ([self isSecure]) if ([self isSecure])
@@ -237,14 +237,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurFunction; CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurFunction;
} }
CPTextFieldDOMInputElement = CPTextFieldDOMPasswordInputElement; CPTextFieldDOMInputElement = CPTextFieldDOMPasswordInputElement;
} }
else else
{ {
CPTextFieldDOMInputElement = CPTextFieldDOMStandardInputElement; CPTextFieldDOMInputElement = CPTextFieldDOMStandardInputElement;
} }
return CPTextFieldDOMInputElement; return CPTextFieldDOMInputElement;
} }
#endif #endif
@@ -262,18 +262,29 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"]; [self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"];
} }
return self; return self;
} }
#pragma mark Controlling Editability and Selectability #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 - (void)setEditable:(BOOL)shouldBeEditable
{ {
if (_isEditable === shouldBeEditable)
return;
_isEditable = shouldBeEditable; _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; 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. Sets whether the field's text is selectable by the user.
@param aFlag \c YES makes the text selectable @param aFlag \c YES makes the text selectable
@@ -346,7 +370,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setBezelStyle:(CPTextFieldBezelStyle)aBezelStyle - (void)setBezelStyle:(CPTextFieldBezelStyle)aBezelStyle
{ {
var shouldBeRounded = aBezelStyle === CPTextFieldRoundedBezel; var shouldBeRounded = aBezelStyle === CPTextFieldRoundedBezel;
if (shouldBeRounded) if (shouldBeRounded)
[self setThemeState:CPTextFieldStateRounded]; [self setThemeState:CPTextFieldStateRounded];
else else
@@ -392,9 +416,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{ {
if (_drawsBackground == shouldDrawBackground) if (_drawsBackground == shouldDrawBackground)
return; return;
_drawsBackground = shouldDrawBackground; _drawsBackground = shouldDrawBackground;
[self setNeedsLayout]; [self setNeedsLayout];
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
} }
@@ -415,9 +439,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{ {
if (_textFieldBackgroundColor == aColor) if (_textFieldBackgroundColor == aColor)
return; return;
_textFieldBackgroundColor = aColor; _textFieldBackgroundColor = aColor;
[self setNeedsLayout]; [self setNeedsLayout];
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
} }
@@ -480,24 +504,31 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
_DOMElement.appendChild(element); _DOMElement.appendChild(element);
window.setTimeout(function() window.setTimeout(function()
{ {
element.focus(); 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]]; [self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
CPTextFieldInputOwner = self; CPTextFieldInputOwner = self;
}, 0.0); }, 0.0);
element.value = [self stringValue]; element.value = [self stringValue];
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES]; [[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
CPTextFieldInputIsActive = YES; CPTextFieldInputIsActive = YES;
if (document.attachEvent) if (document.attachEvent)
{ {
CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart; CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag; CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
[[self window] platformWindow]._DOMBodyElement.ondrag = function () {}; [[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
[[self window] platformWindow]._DOMBodyElement.onselectstart = function () {}; [[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
} }
@@ -519,14 +550,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var element = [self _inputElement]; var element = [self _inputElement];
[self setObjectValue:element.value]; if ([self stringValue] !== element.value)
[self _setStringValue:element.value];
CPTextFieldInputResigning = YES; CPTextFieldInputResigning = YES;
element.blur(); element.blur();
if (!CPTextFieldInputDidBlur) if (!CPTextFieldInputDidBlur)
CPTextFieldBlurFunction(); CPTextFieldBlurFunction();
CPTextFieldInputDidBlur = NO; CPTextFieldInputDidBlur = NO;
CPTextFieldInputResigning = NO; CPTextFieldInputResigning = NO;
@@ -537,13 +569,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
if (document.attachEvent) if (document.attachEvent)
{ {
CPTextFieldCachedSelectStartFunction = nil;
CPTextFieldCachedDragFunction = nil;
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction; [[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction; [[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
CPTextFieldCachedSelectStartFunction = nil;
CPTextFieldCachedDragFunction = nil;
} }
#endif #endif
//post CPControlTextDidEndEditingNotification //post CPControlTextDidEndEditingNotification
@@ -573,21 +605,50 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{ {
// Don't track! (ever?) // Don't track! (ever?)
if ([self isEditable] && [self isEnabled]) 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 else
return [[self nextResponder] mouseDown:anEvent]; return [[self nextResponder] mouseDown:anEvent];
} }
- (void)mouseUp:(CPEvent)anEvent - (void)mouseUp:(CPEvent)anEvent
{ {
if (![self isEditable] || ![self isEnabled]) if (![self isSelectable] && (![self isEditable] || ![self isEnabled]))
[[self nextResponder] mouseUp:anEvent]; [[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 - (void)mouseDragged:(CPEvent)anEvent
{ {
if (![self isEditable] || ![self isEnabled]) if (![self isSelectable] && (![self isEditable] || ![self isEnabled]))
[[self nextResponder] mouseDragged:anEvent]; [[self nextResponder] mouseDragged:anEvent];
else if ([self isSelectable])
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
} }
- (void)keyUp:(CPEvent)anEvent - (void)keyUp:(CPEvent)anEvent
@@ -624,29 +685,16 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO]; [[[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 else
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES]; [[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
} }
- (void)textDidBlur:(CPNotification)note - (void)textDidBlur:(CPNotification)note
{ {
//this looks to prevent false propagation of notifications for other objects // this looks to prevent false propagation of notifications for other objects
if([note object] != self) if ([note object] != self)
return; return;
[[CPNotificationCenter defaultCenter] postNotification:note]; [[CPNotificationCenter defaultCenter] postNotification:note];
@@ -654,13 +702,22 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)textDidFocus:(CPNotification)note - (void)textDidFocus:(CPNotification)note
{ {
//this looks to prevent false propagation of notifications for other objects // this looks to prevent false propagation of notifications for other objects
if([note object] != self) if ([note object] != self)
return; return;
[[CPNotificationCenter defaultCenter] postNotification:note]; [[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. Returns the string the text field.
*/ */
@@ -683,7 +740,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setObjectValue:(id)aValue - (void)setObjectValue:(id)aValue
{ {
[super setObjectValue:aValue]; [super setObjectValue:aValue];
#if PLATFORM(DOM) #if PLATFORM(DOM)
if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self) 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, 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 and after editing ends, if the text field has an empty string value
*/ */
-(void)setPlaceholderString:(CPString)aStringValue - (void)setPlaceholderString:(CPString)aStringValue
{ {
if (_placeholderString === aStringValue) if (_placeholderString === aStringValue)
return; return;
_placeholderString = aStringValue; _placeholderString = aStringValue;
// Only update things if we need to show the placeholder // Only update things if we need to show the placeholder
@@ -730,43 +787,101 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return _placeholderString; 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-bezeled text fields (typically a label), sizeToFit has two behaviors, depending
on the line break mode of the receiver.
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 For non-bezeled receivers with a non-wrapping line break mode, sizeToFit will change the frame of the
the current theme values for content-inset, min-size, and max-size. 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,
For editable text fields, sizeToFit will ONLY change the HEIGHT of the text field. It will not sizeToFit will wrap the text within the current width (respecting the current content-inset),
change the width of the text field. You can use setFrameSize: with the current height to set the so it will ONLY change the HEIGHT.
width, and you can get the size of a string with [CPString sizeWithFont:].
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 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 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. useful for making the textfield an appropriate height.
*/ */
- (void)sizeToFit - (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"], contentInset = [self currentValueForThemeAttribute:@"content-inset"],
minSize = [self currentValueForThemeAttribute:@"min-size"], 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); textSize.width -= contentInset.left + contentInset.right;
size.height = MAX(size.height + contentInset.top + contentInset.bottom, minSize.height); textSize.height -= contentInset.top + contentInset.bottom;
if (maxSize.width >= 0.0) if (frameSize.width !== 0 &&
size.width = MIN(size.width, maxSize.width); ![self isBezeled] &&
(lineBreakMode === CPLineBreakByWordWrapping || lineBreakMode === CPLineBreakByCharWrapping))
{
textSize = [text sizeWithFont:font inWidth:textSize.width];
}
else
textSize = [text sizeWithFont:font];
if (maxSize.height >= 0.0) frameSize.height = textSize.height + contentInset.top + contentInset.bottom;
size.height = MIN(size.height, maxSize.height);
if ([self isEditable]) if ([self isBezeled])
size.width = CGRectGetWidth([self frame]); {
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) #if PLATFORM(DOM)
var element = [self _inputElement]; var element = [self _inputElement];
if (([self isEditable] || [self isSelectable])) if (([self isEditable] || [self isSelectable]))
{ {
if ([[self window] firstResponder] === self) if ([[self window] firstResponder] === self)
window.setTimeout(function() { element.select(); }, 0); window.setTimeout(function() { element.select(); }, 0);
else else if ([self window] !== nil && [[self window] makeFirstResponder:self])
{
[[self window] makeFirstResponder:self];
window.setTimeout(function() {[self selectText:sender];}, 0); window.setTimeout(function() {[self selectText:sender];}, 0);
}
} }
#endif #endif
} }
@@ -834,7 +946,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString]; newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
[self setStringValue:newValue]; [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); return CPMakeRange(0, 0);
// we wrap this in try catch because firefox will throw an exception in certain instances // we wrap this in try catch because firefox will throw an exception in certain instances
try try
{ {
var inputElement = [self _inputElement], var inputElement = [self _inputElement],
selectionStart = inputElement.selectionStart, selectionStart = inputElement.selectionStart,
selectionEnd = inputElement.selectionEnd; selectionEnd = inputElement.selectionEnd;
if ([selectionStart isKindOfClass:CPNumber]) if ([selectionStart isKindOfClass:CPNumber])
return CPMakeRange(selectionStart, selectionEnd - selectionStart); return CPMakeRange(selectionStart, selectionEnd - selectionStart);
// browsers which don't support selectionStart/selectionEnd (aka IE). // browsers which don't support selectionStart/selectionEnd (aka IE).
var theDocument = inputElement.ownerDocument || inputElement.document, var theDocument = inputElement.ownerDocument || inputElement.document,
@@ -863,8 +975,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
range.setEndPoint('EndToStart', selectionRange); range.setEndPoint('EndToStart', selectionRange);
return CPMakeRange(range.text.length, selectionRange.text.length); return CPMakeRange(range.text.length, selectionRange.text.length);
} }
} }
catch (e) catch (e)
{ {
// fall through to the return // fall through to the return
} }
@@ -879,7 +991,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var inputElement = [self _inputElement]; var inputElement = [self _inputElement];
try try
{ {
if ([inputElement.selectionStart isKindOfClass:CPNumber]) if ([inputElement.selectionStart isKindOfClass:CPNumber])
{ {
@@ -892,7 +1004,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var theDocument = inputElement.ownerDocument || inputElement.document, var theDocument = inputElement.ownerDocument || inputElement.document,
existingRange = theDocument.selection.createRange(), existingRange = theDocument.selection.createRange(),
range = inputElement.createTextRange(); range = inputElement.createTextRange();
if (range.inRange(existingRange)) if (range.inRange(existingRange))
{ {
range.collapse(true); range.collapse(true);
@@ -927,7 +1039,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setDelegate:(id)aDelegate - (void)setDelegate:(id)aDelegate
{ {
var defaultCenter = [CPNotificationCenter defaultCenter]; var defaultCenter = [CPNotificationCenter defaultCenter];
//unsubscribe the existing delegate if it exists //unsubscribe the existing delegate if it exists
if (_delegate) if (_delegate)
{ {
@@ -937,24 +1049,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[defaultCenter removeObserver:_delegate name:CPTextFieldDidFocusNotification object:self]; [defaultCenter removeObserver:_delegate name:CPTextFieldDidFocusNotification object:self];
[defaultCenter removeObserver:_delegate name:CPTextFieldDidBlurNotification object:self]; [defaultCenter removeObserver:_delegate name:CPTextFieldDidBlurNotification object:self];
} }
_delegate = aDelegate; _delegate = aDelegate;
if ([_delegate respondsToSelector:@selector(controlTextDidBeginEditing:)]) if ([_delegate respondsToSelector:@selector(controlTextDidBeginEditing:)])
[defaultCenter [defaultCenter
addObserver:_delegate addObserver:_delegate
selector:@selector(controlTextDidBeginEditing:) selector:@selector(controlTextDidBeginEditing:)
name:CPControlTextDidBeginEditingNotification name:CPControlTextDidBeginEditingNotification
object:self]; object:self];
if ([_delegate respondsToSelector:@selector(controlTextDidChange:)]) if ([_delegate respondsToSelector:@selector(controlTextDidChange:)])
[defaultCenter [defaultCenter
addObserver:_delegate addObserver:_delegate
selector:@selector(controlTextDidChange:) selector:@selector(controlTextDidChange:)
name:CPControlTextDidChangeNotification name:CPControlTextDidChangeNotification
object:self]; object:self];
if ([_delegate respondsToSelector:@selector(controlTextDidEndEditing:)]) if ([_delegate respondsToSelector:@selector(controlTextDidEndEditing:)])
[defaultCenter [defaultCenter
addObserver:_delegate addObserver:_delegate
@@ -985,30 +1097,30 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (CGRect)contentRectForBounds:(CGRect)bounds - (CGRect)contentRectForBounds:(CGRect)bounds
{ {
var contentInset = [self currentValueForThemeAttribute:@"content-inset"]; var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
if (!contentInset) if (!contentInset)
return bounds; return bounds;
bounds.origin.x += contentInset.left; bounds.origin.x += contentInset.left;
bounds.origin.y += contentInset.top; bounds.origin.y += contentInset.top;
bounds.size.width -= contentInset.left + contentInset.right; bounds.size.width -= contentInset.left + contentInset.right;
bounds.size.height -= contentInset.top + contentInset.bottom; bounds.size.height -= contentInset.top + contentInset.bottom;
return bounds; return bounds;
} }
- (CGRect)bezelRectForBounds:(CFRect)bounds - (CGRect)bezelRectForBounds:(CGRect)bounds
{ {
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"]; var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
if (_CGInsetIsEmpty(bezelInset)) if (_CGInsetIsEmpty(bezelInset))
return bounds; return bounds;
bounds.origin.x += bezelInset.left; bounds.origin.x += bezelInset.left;
bounds.origin.y += bezelInset.top; bounds.origin.y += bezelInset.top;
bounds.size.width -= bezelInset.left + bezelInset.right; bounds.size.width -= bezelInset.left + bezelInset.right;
bounds.size.height -= bezelInset.top + bezelInset.bottom; bounds.size.height -= bezelInset.top + bezelInset.bottom;
return bounds; return bounds;
} }
@@ -1016,10 +1128,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{ {
if (aName === "bezel-view") if (aName === "bezel-view")
return [self bezelRectForBounds:[self bounds]]; return [self bezelRectForBounds:[self bounds]];
else if (aName === "content-view") else if (aName === "content-view")
return [self contentRectForBounds:[self bounds]]; return [self contentRectForBounds:[self bounds]];
return [super rectForEphemeralSubviewNamed:aName]; return [super rectForEphemeralSubviewNamed:aName];
} }
@@ -1030,19 +1142,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()]; var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO]; [view setHitTests:NO];
return view; return view;
} }
else else
{ {
var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()]; var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
//[view setImagePosition:CPNoImage]; //[view setImagePosition:CPNoImage];
[view setHitTests:NO]; [view setHitTests:NO];
return view; return view;
} }
return [super createEphemeralSubviewNamed:aName]; return [super createEphemeralSubviewNamed:aName];
} }
@@ -1051,10 +1163,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view" var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
positioned:CPWindowBelow positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:@"content-view"]; relativeToEphemeralSubviewNamed:@"content-view"];
if (bezelView) if (bezelView)
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]]; [bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
var contentView = [self layoutEphemeralSubviewNamed:@"content-view" var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
positioned:CPWindowAbove positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"bezel-view"]; relativeToEphemeralSubviewNamed:@"bezel-view"];
@@ -1064,7 +1176,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[contentView setHidden:[self hasThemeState:CPThemeStateEditing]]; [contentView setHidden:[self hasThemeState:CPThemeStateEditing]];
var string = ""; var string = "";
if ([self hasThemeState:CPTextFieldStatePlaceholder]) if ([self hasThemeState:CPTextFieldStatePlaceholder])
string = [self placeholderString]; string = [self placeholderString];
else 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 @end
var secureStringForString = function(aString) var secureStringForString = function(aString)
@@ -1095,7 +1223,7 @@ var secureStringForString = function(aString)
if (!aString) if (!aString)
return ""; return "";
return Array(aString.length+1).join(CPSecureTextFieldCharacter); return Array(aString.length + 1).join(CPSecureTextFieldCharacter);
} }
@@ -1106,6 +1234,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
CPTextFieldBezelStyleKey = "CPTextFieldBezelStyleKey", CPTextFieldBezelStyleKey = "CPTextFieldBezelStyleKey",
CPTextFieldDrawsBackgroundKey = "CPTextFieldDrawsBackgroundKey", CPTextFieldDrawsBackgroundKey = "CPTextFieldDrawsBackgroundKey",
CPTextFieldLineBreakModeKey = "CPTextFieldLineBreakModeKey", CPTextFieldLineBreakModeKey = "CPTextFieldLineBreakModeKey",
CPTextFieldAlignmentKey = "CPTextFieldAlignmentKey",
CPTextFieldBackgroundColorKey = "CPTextFieldBackgroundColorKey", CPTextFieldBackgroundColorKey = "CPTextFieldBackgroundColorKey",
CPTextFieldPlaceholderStringKey = "CPTextFieldPlaceholderStringKey"; CPTextFieldPlaceholderStringKey = "CPTextFieldPlaceholderStringKey";
@@ -1119,7 +1248,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super initWithCoder:aCoder]; self = [super initWithCoder:aCoder];
if (self) if (self)
{ {
[self setEditable:[aCoder decodeBoolForKey:CPTextFieldIsEditableKey]]; [self setEditable:[aCoder decodeBoolForKey:CPTextFieldIsEditableKey]];
@@ -1129,9 +1258,24 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
[self setTextFieldBackgroundColor:[aCoder decodeObjectForKey:CPTextFieldBackgroundColorKey]]; [self setTextFieldBackgroundColor:[aCoder decodeObjectForKey:CPTextFieldBackgroundColorKey]];
[self setLineBreakMode:[aCoder decodeIntForKey:CPTextFieldLineBreakModeKey]];
[self setAlignment:[aCoder decodeIntForKey:CPTextFieldAlignmentKey]];
[self setPlaceholderString:[aCoder decodeObjectForKey:CPTextFieldPlaceholderStringKey]]; [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; return self;
} }
@@ -1142,14 +1286,17 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeBool:_isEditable forKey:CPTextFieldIsEditableKey]; [aCoder encodeBool:_isEditable forKey:CPTextFieldIsEditableKey];
[aCoder encodeBool:_isSelectable forKey:CPTextFieldIsSelectableKey]; [aCoder encodeBool:_isSelectable forKey:CPTextFieldIsSelectableKey];
[aCoder encodeBool:_drawsBackground forKey:CPTextFieldDrawsBackgroundKey]; [aCoder encodeBool:_drawsBackground forKey:CPTextFieldDrawsBackgroundKey];
[aCoder encodeObject:_textFieldBackgroundColor forKey:CPTextFieldBackgroundColorKey]; [aCoder encodeObject:_textFieldBackgroundColor forKey:CPTextFieldBackgroundColorKey];
[aCoder encodeInt:[self lineBreakMode] forKey:CPTextFieldLineBreakModeKey];
[aCoder encodeInt:[self alignment] forKey:CPTextFieldAlignmentKey];
[aCoder encodeObject:_placeholderString forKey:CPTextFieldPlaceholderStringKey]; [aCoder encodeObject:_placeholderString forKey:CPTextFieldPlaceholderStringKey];
} }
+188 -20
View File
@@ -24,8 +24,10 @@
@import <Foundation/CPString.j> @import <Foundation/CPString.j>
@import <Foundation/CPKeyedUnarchiver.j> @import <Foundation/CPKeyedUnarchiver.j>
var CPThemesByName = { },
CPThemeDefaultTheme = nil; var CPThemesByName = { },
CPThemeDefaultTheme = nil,
CPThemeDefaultHudTheme = nil;
/*! /*!
@@ -48,6 +50,27 @@ var CPThemesByName = { },
return CPThemeDefaultTheme; 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 + (CPTheme)themeNamed:(CPString)aName
{ {
return CPThemesByName[aName]; return CPThemesByName[aName];
@@ -73,9 +96,110 @@ var CPThemesByName = { },
return _name; 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) if (!attributes)
return nil; return nil;
@@ -83,12 +207,53 @@ var CPThemesByName = { },
return [attributes objectForKey:aName]; 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 - (void)takeThemeFromObject:(id)anObject
{ {
var attributes = [anObject _themeAttributeDictionary], var attributes = [anObject _themeAttributeDictionary],
attributeName = nil, attributeName = nil,
attributeNames = [attributes keyEnumerator], attributeNames = [attributes keyEnumerator],
objectThemeClass = [[anObject class] themeClass]; objectThemeClass = [anObject themeClass];
while (attributeName = [attributeNames nextObject]) while (attributeName = [attributeNames nextObject])
[self _recordAttribute:[attributes objectForKey:attributeName] forClass:objectThemeClass]; [self _recordAttribute:[attributes objectForKey:attributeName] forClass:objectThemeClass];
@@ -242,6 +407,9 @@ CPThemeStateNormal = CPThemeStates["normal"] = 0;
CPThemeStateDisabled = CPThemeState("disabled"); CPThemeStateDisabled = CPThemeState("disabled");
CPThemeStateHighlighted = CPThemeState("highlighted"); CPThemeStateHighlighted = CPThemeState("highlighted");
CPThemeStateSelected = CPThemeState("selected"); CPThemeStateSelected = CPThemeState("selected");
CPThemeStateTableDataView = CPThemeState("tableDataView");
CPThemeStateSelectedDataView = CPThemeStateSelectedTableDataView = CPThemeState("selectedTableDataView");
CPThemeStateGroupRow = CPThemeState("CPThemeStateGroupRow");
CPThemeStateBezeled = CPThemeState("bezeled"); CPThemeStateBezeled = CPThemeState("bezeled");
CPThemeStateBordered = CPThemeState("bordered"); CPThemeStateBordered = CPThemeState("bordered");
CPThemeStateEditable = CPThemeState("editable"); CPThemeStateEditable = CPThemeState("editable");
@@ -254,10 +422,10 @@ CPThemeStateCircular = CPThemeState("circular");
{ {
CPString _name; CPString _name;
id _defaultValue; id _defaultValue;
CPDictionary _values; CPDictionary _values @accessors(readonly, getter=values);
JSObject _cache; JSObject _cache;
CPThemeAttribute _parentAttribute; _CPThemeAttribute _parentAttribute;
} }
- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue - (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue
@@ -378,7 +546,7 @@ CPThemeStateCircular = CPThemeState("circular");
return value; return value;
} }
- (void)setParentAttribute:(CPThemeAttribute)anAttribute - (void)setParentAttribute:(_CPThemeAttribute)anAttribute
{ {
if (_parentAttribute === anAttribute) if (_parentAttribute === anAttribute)
return; return;
@@ -387,7 +555,7 @@ CPThemeStateCircular = CPThemeState("circular");
_parentAttribute = anAttribute; _parentAttribute = anAttribute;
} }
- (CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute - (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
{ {
var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue]; var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue];
@@ -472,15 +640,15 @@ CPThemeStateCircular = CPThemeState("circular");
@end @end
var cachedNumberOfOnes = [ 0 /*000000*/, 1 /*000001*/, 1 /*000010*/, 2 /*000011*/, 1 /*000100*/, 2 /*000101*/, 2 /*000110*/, 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 /*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 /*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 /*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 /*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 /*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 /*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 /*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*/, 3 /*111000*/, 4 /*111001*/, 4 /*111010*/, 5 /*111011*/, 4 /*111100*/, 5 /*111101*/, 5 /*111110*/,
6 /*111111*/ ]; 6 /*111111*/ ];
var numberOfOnes = function(aNumber) var numberOfOnes = function(aNumber)
@@ -551,7 +719,7 @@ function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme,
} }
if (aTheme && aClass) if (aTheme && aClass)
[attribute setParentAttribute:[aTheme _attributeWithName:anAttributeName forClass:aClass]]; [attribute setParentAttribute:[aTheme attributeWithName:anAttributeName forClass:aClass]];
return attribute; return attribute;
} }
@@ -585,4 +753,4 @@ for (i = 0;i < Math.pow(2,6);++i)
} }
print(str+']'); print(str+']');
*/ */
+34 -10
View File
@@ -22,9 +22,10 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import <AppKit/CPTheme.j> @import "CPTheme.j"
@import <AppKit/_CPCibCustomResource.j> @import "_CPCibCustomResource.j"
@import <AppKit/_CPCibKeyedUnarchiver.j> @import "_CPCibKeyedUnarchiver.j"
/*! /*!
@ingroup appkit @ingroup appkit
@@ -33,37 +34,60 @@
@implementation CPThemeBlend : CPObject @implementation CPThemeBlend : CPObject
{ {
CPBundle _bundle; CPBundle _bundle;
CPArray _themes @accessors(readonly, getter=themes); CPArray _themes;
id _loadDelegate; id _loadDelegate;
} }
- (id)initWithContentsOfURL:(CPURL)aURL - (id)initWithContentsOfURL:(CPURL)aURL
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_bundle = [[CPBundle alloc] initWithPath:aURL]; _bundle = [[CPBundle alloc] initWithPath:aURL];
} }
return self; 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 - (void)loadWithDelegate:(id)aDelegate
{ {
_loadDelegate = aDelegate; _loadDelegate = aDelegate;
[_bundle loadWithDelegate:self]; [_bundle loadWithDelegate:self];
} }
- (void)bundleDidFinishLoading:(CPBundle)aBundle - (void)bundleDidFinishLoading:(CPBundle)aBundle
{ {
var themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"], _themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"];
count = themes.length;
var count = _themes.length;
while (count--) while (count--)
{ {
var path = [aBundle pathForResource:themes[count]], var path = [aBundle pathForResource:_themes[count]],
unarchiver = [[_CPThemeKeyedUnarchiver alloc] unarchiver = [[_CPThemeKeyedUnarchiver alloc]
initForReadingWithData:[[CPURL URLWithString:path] staticResourceData] initForReadingWithData:[[CPURL URLWithString:path] staticResourceData]
bundle:_bundle]; 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 "CPPopUpButton.j"
@import "CPToolbarItem.j" @import "CPToolbarItem.j"
#include "CoreGraphics/CGGeometry.h"
/* /*
@global @global
@@ -329,7 +327,11 @@ var CPToolbarConfigurationsByIdentifier = nil;
return _itemsSortedByVisibilityPriority; 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], var toolbarItems = [self visibleItems],
count = [toolbarItems count]; count = [toolbarItems count];
@@ -466,7 +468,14 @@ var CPToolbarIdentifierKey = @"CPToolbarIdentifierKey",
// specified, it will be read later and the resulting call to -setDelegate: // specified, it will be read later and the resulting call to -setDelegate:
// will cause -_reloadToolbarItems] to run again :-( // will cause -_reloadToolbarItems] to run again :-(
// FIXME: Can we make this better? // 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; return self;
@@ -559,6 +568,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
[_additionalItemsButton setImagePosition:CPImageOnly]; [_additionalItemsButton setImagePosition:CPImageOnly];
[[_additionalItemsButton menu] setShowsStateColumn:NO]; [[_additionalItemsButton menu] setShowsStateColumn:NO];
[[_additionalItemsButton menu] setAutoenablesItems:NO];
[_additionalItemsButton setAlternateImage:_CPToolbarViewExtraItemsAlternateImage]; [_additionalItemsButton setAlternateImage:_CPToolbarViewExtraItemsAlternateImage];
} }
@@ -789,14 +799,13 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
hasNonSeparatorItem = YES; hasNonSeparatorItem = YES;
[_additionalItemsButton addItemWithTitle:[item label]]; var menuItem = [[CPMenuItem alloc] initWithTitle:[item label] action:[item action] keyEquivalent:nil];
var menuItem = [_additionalItemsButton itemArray][index + 1];
[menuItem setImage:[item image]]; [menuItem setImage:[item image]];
[menuItem setTarget:[item target]]; [menuItem setTarget:[item target]];
[menuItem setAction:[item action]]; [menuItem setEnabled:[item isEnabled]];
[_additionalItemsButton addItem:menuItem];
} }
} }
else else
@@ -970,7 +979,7 @@ var TOP_MARGIN = 5.0,
{ {
_imageView = [[CPImageView alloc] initWithFrame:[self bounds]]; _imageView = [[CPImageView alloc] initWithFrame:[self bounds]];
[_imageView setImageScaling:CPScaleNone]; [_imageView setImageScaling:CPScaleProportionally];
[self addSubview:_imageView]; [self addSubview:_imageView];
} }
@@ -1051,6 +1060,8 @@ var TOP_MARGIN = 5.0,
[_imageView setAlphaValue:0.5]; [_imageView setAlphaValue:0.5];
[_labelField setAlphaValue:0.5]; [_labelField setAlphaValue:0.5];
} }
[_toolbar tile];
} }
- (CPColor)FIXME_labelColor - (CPColor)FIXME_labelColor
+6 -6
View File
@@ -23,8 +23,9 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import <Foundation/CPString.j> @import <Foundation/CPString.j>
@import <AppKit/CPImage.j> @import "CPImage.j"
@import <AppKit/CPView.j> @import "CPView.j"
CPToolbarItemVisibilityPriorityStandard = 0; CPToolbarItemVisibilityPriorityStandard = 0;
CPToolbarItemVisibilityPriorityLow = -1000; CPToolbarItemVisibilityPriorityLow = -1000;
@@ -449,6 +450,9 @@ CPToolbarItemVisibilityPriorityUser
- (void)validate - (void)validate
{ {
var action = [self action],
target = [self target];
// View items do not do any target-action analysis. // View items do not do any target-action analysis.
if (_view) if (_view)
{ {
@@ -458,13 +462,9 @@ CPToolbarItemVisibilityPriorityUser
return; return;
} }
var action = [self action];
if (!action) if (!action)
return [self setEnabled:NO]; return [self setEnabled:NO];
var target = [self target];
if (target && ![target respondsToSelector:action]) if (target && ![target respondsToSelector:action])
return [self setEnabled:NO]; return [self setEnabled:NO];
+197
View File
@@ -87,6 +87,40 @@
[_childNodes[count] sortWithSortDescriptors:sortDescriptors recursively:YES]; [_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 @end
var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey", var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
@@ -117,3 +151,166 @@ var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
} }
@end @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
+326 -215
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 * AppKit
* *
* Created by Klaas Pieter Annema on September 3, 2009. * 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 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import <AppKit/CPAnimation.j> @import "CPAnimation.j"
CPViewAnimationTargetKey = @"CPViewAnimationTarget"; CPViewAnimationTargetKey = @"CPViewAnimationTarget";
CPViewAnimationStartFrameKey = @"CPViewAnimationStartFrame"; CPViewAnimationStartFrameKey = @"CPViewAnimationStartFrame";
@@ -69,7 +70,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
[super startAnimation]; [super startAnimation];
} }
- (void)setCurrentProgress:(NSAnimationProgress)progress - (void)setCurrentProgress:(CPAnimationProgress)progress
{ {
[super setCurrentProgress:progress]; [super setCurrentProgress:progress];
@@ -77,17 +78,17 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
while (animationIndex--) while (animationIndex--)
{ {
var dictionary = [_viewAnimations objectAtIndex:animationIndex], var dictionary = [_viewAnimations objectAtIndex:animationIndex],
view = [self _targetView:dictionary] view = [self _targetView:dictionary],
startFrame = [self _startFrame:dictionary] startFrame = [self _startFrame:dictionary],
endFrame = [self _endFrame:dictionary] endFrame = [self _endFrame:dictionary],
differenceFrame = CPRectMakeZero(); differenceFrame = _CGRectMakeZero();
differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x; differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x;
differenceFrame.origin.y = endFrame.origin.y - startFrame.origin.y; differenceFrame.origin.y = endFrame.origin.y - startFrame.origin.y;
differenceFrame.size.width = endFrame.size.width - startFrame.size.width; differenceFrame.size.width = endFrame.size.width - startFrame.size.width;
differenceFrame.size.height = endFrame.size.height - startFrame.size.height; 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.x = startFrame.origin.x + differenceFrame.origin.x * progress;
intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * progress; intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * progress;
intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * 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]; [view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress];
if (progress === 1.0) 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) else if (effect === CPViewAnimationFadeOutEffect)
[view setAlphaValue:0.0]; [view setAlphaValue:0.0];
[view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0]; [view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
} }
[super stopAnimation]; [super stopAnimation];
@@ -139,7 +140,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
return targetView; return targetView;
} }
- (CPRect)_startFrame:(CPDictionary)dictionary - (CGRect)_startFrame:(CPDictionary)dictionary
{ {
var startFrame = [dictionary valueForKey:CPViewAnimationStartFrameKey]; var startFrame = [dictionary valueForKey:CPViewAnimationStartFrameKey];
if (!startFrame) if (!startFrame)
@@ -148,7 +149,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
return startFrame; return startFrame;
} }
- (CPRect)_endFrame:(CPDictionary)dictionary - (CGRect)_endFrame:(CPDictionary)dictionary
{ {
var endFrame = [dictionary valueForKey:CPViewAnimationEndFrameKey]; var endFrame = [dictionary valueForKey:CPViewAnimationEndFrameKey];
if (!endFrame) if (!endFrame)
+24 -7
View File
@@ -20,7 +20,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 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; var CPViewControllerCachedCibs;
@@ -47,7 +52,8 @@ var CPViewControllerCachedCibs;
*/ */
@implementation CPViewController : CPResponder @implementation CPViewController : CPResponder
{ {
CPView _view; CPView _view @accessors(property=view);
BOOL _isLoading;
id _representedObject @accessors(property=representedObject); id _representedObject @accessors(property=representedObject);
CPString _title @accessors(property=title); CPString _title @accessors(property=title);
@@ -99,6 +105,8 @@ var CPViewControllerCachedCibs;
_cibName = aCibNameOrNil; _cibName = aCibNameOrNil;
_cibBundle = aCibBundleOrNil || [CPBundle mainBundle]; _cibBundle = aCibBundleOrNil || [CPBundle mainBundle];
_cibExternalNameTable = anExternalNameTable || [CPDictionary dictionaryWithObject:self forKey:CPCibOwner]; _cibExternalNameTable = anExternalNameTable || [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
_isLoading = NO;
} }
return self; 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. 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. 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 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. 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 - (void)loadView
{ {
if (_view) if (_view)
return; return;
// check if a cib is already cached for the current _cibName // check if a cib is already cached for the current _cibName
var cib = [CPViewControllerCachedCibs objectForKey:_cibName]; var cib = [CPViewControllerCachedCibs objectForKey:_cibName];
@@ -143,6 +151,8 @@ var CPViewControllerCachedCibs;
{ {
if (!_view) if (!_view)
{ {
_isLoading = YES;
var cibOwner = [_cibExternalNameTable objectForKey:CPCibOwner]; var cibOwner = [_cibExternalNameTable objectForKey:CPCibOwner];
if ([cibOwner respondsToSelector:@selector(viewControllerWillLoadCib:)]) if ([cibOwner respondsToSelector:@selector(viewControllerWillLoadCib:)])
@@ -163,6 +173,7 @@ var CPViewControllerCachedCibs;
if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)]) if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)])
[cibOwner viewControllerDidLoadCib:self]; [cibOwner viewControllerDidLoadCib:self];
_isLoading = NO;
[self viewDidLoad]; [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 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 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 - (void)viewDidLoad
{ {
@@ -189,7 +200,13 @@ var CPViewControllerCachedCibs;
*/ */
- (void)setView:(CPView)aView - (void)setView:(CPView)aView
{ {
var viewWasLoaded = !_view;
_view = aView; _view = aView;
// Make sure the viewDidLoad method is called if the view is set directly
if (!_isLoading && viewWasLoaded)
[self viewDidLoad];
} }
@end @end
+100 -56
View File
@@ -20,9 +20,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import <AppKit/CPView.j> @import "CPView.j"
@import "CPScrollView.j"
#include "Platform/Platform.h"
// FIXME: implement these where possible: // FIXME: implement these where possible:
@@ -50,30 +49,32 @@ CPWebViewScrollNative = 2;
{ {
CPScrollView _scrollView; CPScrollView _scrollView;
CPView _frameView; CPView _frameView;
IFrame _iframe; IFrame _iframe;
CPString _mainFrameURL; CPString _mainFrameURL;
CPArray _backwardStack; CPArray _backwardStack;
CPArray _forwardStack; CPArray _forwardStack;
BOOL _ignoreLoadStart; BOOL _ignoreLoadStart;
BOOL _ignoreLoadEnd; BOOL _ignoreLoadEnd;
id _downloadDelegate; id _downloadDelegate;
id _frameLoadDelegate; id _frameLoadDelegate;
id _policyDelegate; id _policyDelegate;
id _resourceLoadDelegate; id _resourceLoadDelegate;
id _UIDelegate; id _UIDelegate;
CPWebScriptObject _wso; CPWebScriptObject _wso;
CPString _url; CPString _url;
CPString _html; CPString _html;
Function _loadCallback; Function _loadCallback;
int _scrollMode; int _scrollMode;
CGSize _scrollSize; CGSize _scrollSize;
int _loadHTMLStringTimer;
} }
- (id)initWithFrame:(CPRect)frameRect frameName:(CPString)frameName groupName:(CPString)groupName - (id)initWithFrame:(CPRect)frameRect frameName:(CPString)frameName groupName:(CPString)groupName
@@ -93,10 +94,10 @@ CPWebViewScrollNative = 2;
_backwardStack = []; _backwardStack = [];
_forwardStack = []; _forwardStack = [];
_scrollMode = CPWebViewScrollNative; _scrollMode = CPWebViewScrollNative;
[self _initDOMWithFrame:aFrame]; [self _initDOMWithFrame:aFrame];
} }
return self; return self;
} }
@@ -104,51 +105,52 @@ CPWebViewScrollNative = 2;
{ {
_ignoreLoadStart = YES; _ignoreLoadStart = YES;
_ignoreLoadEnd = YES; _ignoreLoadEnd = YES;
_iframe = document.createElement("iframe"); _iframe = document.createElement("iframe");
_iframe.name = "iframe_" + Math.floor(Math.random()*10000); _iframe.name = "iframe_" + Math.floor(Math.random()*10000);
_iframe.style.width = "100%"; _iframe.style.width = "100%";
_iframe.style.height = "100%"; _iframe.style.height = "100%";
_iframe.style.borderWidth = "0px"; _iframe.style.borderWidth = "0px";
_iframe.frameBorder = "0";
[self setDrawsBackground:YES]; [self setDrawsBackground:YES];
_loadCallback = function() { _loadCallback = function() {
// HACK: this block handles the case where we don't know about loads initiated by the user clicking a link // HACK: this block handles the case where we don't know about loads initiated by the user clicking a link
if (!_ignoreLoadStart) if (!_ignoreLoadStart)
{ {
// post the start load notification // post the start load notification
[self _startedLoading]; [self _startedLoading];
if (_mainFrameURL) if (_mainFrameURL)
[_backwardStack addObject:_mainFrameURL]; [_backwardStack addObject:_mainFrameURL];
// FIXME: this doesn't actually get the right URL for different domains. Not possible due to browser security restrictions. // 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;
_mainFrameURL = _iframe.src; _mainFrameURL = _iframe.src;
// clear the forward // clear the forward
[_forwardStack removeAllObjects]; [_forwardStack removeAllObjects];
} }
else else
_ignoreLoadStart = NO; _ignoreLoadStart = NO;
if (!_ignoreLoadEnd) if (!_ignoreLoadEnd)
{ {
[self _finishedLoading]; [self _finishedLoading];
} }
else else
_ignoreLoadEnd = NO; _ignoreLoadEnd = NO;
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
} }
if (_iframe.addEventListener) if (_iframe.addEventListener)
_iframe.addEventListener("load", _loadCallback, false); _iframe.addEventListener("load", _loadCallback, false);
else if (_iframe.attachEvent) else if (_iframe.attachEvent)
_iframe.attachEvent("onload", _loadCallback); _iframe.attachEvent("onload", _loadCallback);
_frameView = [[CPView alloc] initWithFrame:[self bounds]]; _frameView = [[CPView alloc] initWithFrame:[self bounds]];
[_frameView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; [_frameView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
@@ -156,9 +158,9 @@ CPWebViewScrollNative = 2;
[_scrollView setAutohidesScrollers:YES]; [_scrollView setAutohidesScrollers:YES];
[_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; [_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_scrollView setDocumentView:_frameView]; [_scrollView setDocumentView:_frameView];
_frameView._DOMElement.appendChild(_iframe); _frameView._DOMElement.appendChild(_iframe);
[self _setScrollMode:_scrollMode]; [self _setScrollMode:_scrollMode];
[self addSubview:_scrollView]; [self addSubview:_scrollView];
@@ -166,12 +168,37 @@ CPWebViewScrollNative = 2;
- (void)setFrameSize:(CPSize)aSize - (void)setFrameSize:(CPSize)aSize
{ {
[super setFrameSize:aSize]; [super setFrameSize:aSize];
[self _resizeWebFrame]; [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) if (_scrollMode === CPWebViewScrollAppKit)
{ {
@@ -181,13 +208,14 @@ CPWebViewScrollNative = 2;
} }
else 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 // try to get the document size so we can correctly set the frame
var win = null; var win = null;
try { win = [self DOMWindow]; } catch (e) {} try { win = [self DOMWindow]; } catch (e) {}
if (win && win.document) if (win && win.document && win.document.body)
{ {
var width = win.document.body.scrollWidth, var width = win.document.body.scrollWidth,
height = win.document.body.scrollHeight; height = win.document.body.scrollHeight;
@@ -200,9 +228,11 @@ CPWebViewScrollNative = 2;
else else
{ {
CPLog.warn("using default size 800*1600"); CPLog.warn("using default size 800*1600");
[_frameView setFrameSize:CGSizeMake(800, 1600)]; [_frameView setFrameSize:CGSizeMake(800, 1600)];
} }
[_frameView scrollRectToVisible:visibleRect];
} }
} }
} }
@@ -211,14 +241,17 @@ CPWebViewScrollNative = 2;
{ {
if (_scrollMode == aScrollMode) if (_scrollMode == aScrollMode)
return; return;
[self _setScrollMode:aScrollMode]; [self _setScrollMode:aScrollMode];
} }
- (void)_setScrollMode:(int)aScrollMode - (void)_setScrollMode:(int)aScrollMode
{ {
_scrollMode = aScrollMode; if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
_scrollMode = CPWebViewScrollNative;
else
_scrollMode = aScrollMode;
_ignoreLoadStart = YES; _ignoreLoadStart = YES;
_ignoreLoadEnd = YES; _ignoreLoadEnd = YES;
@@ -229,16 +262,16 @@ CPWebViewScrollNative = 2;
{ {
[_scrollView setHasHorizontalScroller:YES]; [_scrollView setHasHorizontalScroller:YES];
[_scrollView setHasVerticalScroller:YES]; [_scrollView setHasVerticalScroller:YES];
_iframe.setAttribute("scrolling", "no"); _iframe.setAttribute("scrolling", "no");
} }
else else
{ {
[_scrollView setHasHorizontalScroller:NO]; [_scrollView setHasHorizontalScroller:NO];
[_scrollView setHasVerticalScroller:NO]; [_scrollView setHasVerticalScroller:NO];
_iframe.setAttribute("scrolling", "auto"); _iframe.setAttribute("scrolling", "auto");
[_frameView setFrameSize:[_scrollView bounds].size]; [_frameView setFrameSize:[_scrollView bounds].size];
} }
@@ -256,14 +289,16 @@ CPWebViewScrollNative = 2;
[self _setScrollMode:CPWebViewScrollAppKit]; [self _setScrollMode:CPWebViewScrollAppKit];
[_frameView setFrameSize:[_scrollView contentSize]];
[self _startedLoading]; [self _startedLoading];
_ignoreLoadStart = YES; _ignoreLoadStart = YES;
_ignoreLoadEnd = NO; _ignoreLoadEnd = NO;
_url = null; _url = null;
_html = aString; _html = aString;
[self _load]; [self _load];
} }
@@ -272,13 +307,13 @@ CPWebViewScrollNative = 2;
[self _setScrollMode:CPWebViewScrollNative]; [self _setScrollMode:CPWebViewScrollNative];
[self _startedLoading]; [self _startedLoading];
_ignoreLoadStart = YES; _ignoreLoadStart = YES;
_ignoreLoadEnd = NO; _ignoreLoadEnd = NO;
_url = _mainFrameURL; _url = _mainFrameURL;
_html = null; _html = null;
[self _load]; [self _load];
} }
@@ -293,11 +328,19 @@ CPWebViewScrollNative = 2;
// clear the iframe // clear the iframe
_iframe.src = ""; _iframe.src = "";
// need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document if (_loadHTMLStringTimer !== nil)
window.setTimeout(function() { {
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]; var win = [self DOMWindow];
win.document.write(_html); if (win)
win.document.write(_html);
window.setTimeout(_loadCallback, 1); window.setTimeout(_loadCallback, 1);
}, 0); }, 0);
@@ -315,7 +358,8 @@ CPWebViewScrollNative = 2;
- (void)_finishedLoading - (void)_finishedLoading
{ {
[self _resizeWebFrame]; [self _resizeWebFrame];
[self _attachScrollEventIfNecessary];
[[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressFinishedNotification object:self]; [[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressFinishedNotification object:self];
if ([_frameLoadDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)]) if ([_frameLoadDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)])
@@ -328,7 +372,7 @@ CPWebViewScrollNative = 2;
} }
- (void)setMainFrameURL:(CPString)URLString - (void)setMainFrameURL:(CPString)URLString
{ {
if (_mainFrameURL) if (_mainFrameURL)
[_backwardStack addObject:_mainFrameURL]; [_backwardStack addObject:_mainFrameURL];
_mainFrameURL = URLString; _mainFrameURL = URLString;
@@ -345,9 +389,9 @@ CPWebViewScrollNative = 2;
[_forwardStack addObject:_mainFrameURL]; [_forwardStack addObject:_mainFrameURL];
_mainFrameURL = [_backwardStack lastObject]; _mainFrameURL = [_backwardStack lastObject];
[_backwardStack removeLastObject]; [_backwardStack removeLastObject];
[self _loadMainFrameURL]; [self _loadMainFrameURL];
return YES; return YES;
} }
return NO; return NO;
@@ -361,9 +405,9 @@ CPWebViewScrollNative = 2;
[_backwardStack addObject:_mainFrameURL]; [_backwardStack addObject:_mainFrameURL];
_mainFrameURL = [_forwardStack lastObject]; _mainFrameURL = [_forwardStack lastObject];
[_forwardStack removeLastObject]; [_forwardStack removeLastObject];
[self _loadMainFrameURL]; [self _loadMainFrameURL];
return YES; return YES;
} }
return NO; return NO;
@@ -586,7 +630,7 @@ CPWebViewScrollNative = 2;
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super initWithCoder:aCoder]; self = [super initWithCoder:aCoder];
if (self) if (self)
{ {
// FIXME: encode/decode these? // FIXME: encode/decode these?
@@ -594,14 +638,14 @@ CPWebViewScrollNative = 2;
_backwardStack = []; _backwardStack = [];
_forwardStack = []; _forwardStack = [];
_scrollMode = CPWebViewScrollNative; _scrollMode = CPWebViewScrollNative;
#if PLATFORM(DOM) #if PLATFORM(DOM)
[self _initDOMWithFrame:[self frame]]; [self _initDOMWithFrame:[self frame]];
#endif #endif
[self setBackgroundColor:[CPColor whiteColor]]; [self setBackgroundColor:[CPColor whiteColor]];
} }
return self; return self;
} }
+304 -130
View File
@@ -26,14 +26,9 @@
@import "CGGeometry.j" @import "CGGeometry.j"
@import "CPAnimation.j" @import "CPAnimation.j"
@import "CPPlatformWindow.j"
@import "CPResponder.j" @import "CPResponder.j"
@import "CPScreen.j" @import "CPScreen.j"
@import "CPPlatformWindow.j"
#include "../Platform/Platform.h"
#include "../Platform/DOM/CPDOMDisplayServer.h"
#include "../CoreGraphics/CGGeometry.h"
/* /*
@@ -194,13 +189,15 @@ var SHADOW_MARGIN_LEFT = 20.0,
SHADOW_MARGIN_TOP = 10.0, SHADOW_MARGIN_TOP = 10.0,
SHADOW_MARGIN_BOTTOM = 10.0, SHADOW_MARGIN_BOTTOM = 10.0,
SHADOW_DISTANCE = 5.0, SHADOW_DISTANCE = 5.0,
_CPWindowShadowColor = nil; _CPWindowShadowColor = nil;
var CPWindowSaveImage = nil, var CPWindowSaveImage = nil,
CPWindowSavingImage = nil; CPWindowSavingImage = nil;
/*! var CPWindowResizeTime = 0.2;
/*!
@ingroup appkit @ingroup appkit
@class CPWindow @class CPWindow
@@ -213,33 +210,33 @@ var CPWindowSaveImage = nil,
<p>A window always contains a content view which is the highest level view available for public (application) use. This view fills the area of the window inside any decoration/border. This is the only part of the window that application programmers are allowed to draw in directly.</p> <p>A window always contains a content view which is the highest level view available for public (application) use. This view fills the area of the window inside any decoration/border. This is the only part of the window that application programmers are allowed to draw in directly.</p>
<p>You can convert between view coordinates and window base coordinates using the [CPView -convertPoint:fromView:], [CPView -convertPoint:toView:], [CPView -convertRect:fromView:], and [CPView -convertRect:toView:] methods with a nil view argument. <p>You can convert between view coordinates and window base coordinates using the [CPView -convertPoint:fromView:], [CPView -convertPoint:toView:], [CPView -convertRect:fromView:], and [CPView -convertRect:toView:] methods with a nil view argument.
@par Delegate Methods @par Delegate Methods
@delegate -(void)windowDidResize:(CPNotification)notification; @delegate -(void)windowDidResize:(CPNotification)notification;
Sent from the notification center when the window has been resized. Sent from the notification center when the window has been resized.
@param notification contains information about the resize event @param notification contains information about the resize event
@delegate -(CPUndoManager)windowWillReturnUndoManager:(CPWindow)window; @delegate -(CPUndoManager)windowWillReturnUndoManager:(CPWindow)window;
Called to obtain the undo manager for a window Called to obtain the undo manager for a window
@param window the window for which to return the undo manager @param window the window for which to return the undo manager
@return the window's undo manager @return the window's undo manager
@delegate -(void)windowDidBecomeMain:(CPNotification)notification; @delegate -(void)windowDidBecomeMain:(CPNotification)notification;
Sent from the notification center when the delegate's window becomes Sent from the notification center when the delegate's window becomes
the main window. the main window.
@param notification contains information about the event @param notification contains information about the event
@delegate -(void)windowDidResignMain:(CPNotification)notification; @delegate -(void)windowDidResignMain:(CPNotification)notification;
Sent from the notification center when the delegate's window has Sent from the notification center when the delegate's window has
resigned main window status. resigned main window status.
@param notification contains information about the event @param notification contains information about the event
@delegate -(void)windowDidResignKey:(CPNotification)notification; @delegate -(void)windowDidResignKey:(CPNotification)notification;
Sent from the notification center when the delegate's window has Sent from the notification center when the delegate's window has
resigned key window status. resigned key window status.
@param notification contains information about the event @param notification contains information about the event
@delegate -(BOOL)windowShouldClose:(id)window; @delegate -(BOOL)windowShouldClose:(id)window;
Called when the user tries to close the window. Called when the user tries to close the window.
@param window the window to close @param window the window to close
@@ -311,15 +308,17 @@ var CPWindowSaveImage = nil,
#endif #endif
unsigned _autoresizingMask; unsigned _autoresizingMask;
BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector; BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector;
BOOL _isFullPlatformWindow; BOOL _isFullPlatformWindow;
_CPWindowFullPlatformWindowSession _fullPlatformWindowSession; _CPWindowFullPlatformWindowSession _fullPlatformWindowSession;
CPDictionary _sheetContext; CPDictionary _sheetContext;
CPWindow _parentView; CPWindow _parentView;
BOOL _isSheet; BOOL _isSheet;
_CPWindowFrameAnimation _frameAnimation;
} }
/* /*
@@ -330,9 +329,9 @@ var CPWindowSaveImage = nil,
{ {
if (self != [CPWindow class]) if (self != [CPWindow class])
return; return;
var bundle = [CPBundle bundleForClass:[CPWindow class]]; var bundle = [CPBundle bundleForClass:[CPWindow class]];
CPWindowSavingImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(16.0, 16.0)] CPWindowSavingImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(16.0, 16.0)]
} }
@@ -359,7 +358,7 @@ CPTexturedBackgroundWindowMask
- (id)initWithContentRect:(CGRect)aContentRect styleMask:(unsigned int)aStyleMask - (id)initWithContentRect:(CGRect)aContentRect styleMask:(unsigned int)aStyleMask
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
var windowViewClass = [[self class] _windowViewClassForStyleMask:aStyleMask]; var windowViewClass = [[self class] _windowViewClassForStyleMask:aStyleMask];
@@ -372,6 +371,15 @@ CPTexturedBackgroundWindowMask
[self setPlatformWindow:[CPPlatformWindow primaryPlatformWindow]]; [self setPlatformWindow:[CPPlatformWindow primaryPlatformWindow]];
else else
{ {
// give zero sized borderless bridge windows a default size if we're not in the browser so they show up in NativeHost.
if ((aStyleMask & CPBorderlessBridgeWindowMask) && aContentRect.size.width === 0 && aContentRect.size.height === 0)
{
var visibleFrame = [[[CPScreen alloc] init] visibleFrame];
_frame.size.height = MIN(768.0, visibleFrame.size.height);
_frame.size.width = MIN(1024.0, visibleFrame.size.width);
_frame.origin.x = (visibleFrame.size.width - _frame.size.width) / 2;
_frame.origin.y = (visibleFrame.size.height - _frame.size.height) / 2;
}
[self setPlatformWindow:[[CPPlatformWindow alloc] initWithContentRect:_frame]]; [self setPlatformWindow:[[CPPlatformWindow alloc] initWithContentRect:_frame]];
[self platformWindow]._only = self; [self platformWindow]._only = self;
} }
@@ -384,7 +392,7 @@ CPTexturedBackgroundWindowMask
// Set up our window number. // Set up our window number.
_windowNumber = [CPApp._windows count]; _windowNumber = [CPApp._windows count];
CPApp._windows[_windowNumber] = self; CPApp._windows[_windowNumber] = self;
_styleMask = aStyleMask; _styleMask = aStyleMask;
[self setLevel:CPNormalWindowLevel]; [self setLevel:CPNormalWindowLevel];
@@ -399,15 +407,15 @@ CPTexturedBackgroundWindowMask
[_windowView setNextResponder:self]; [_windowView setNextResponder:self];
[self setMovableByWindowBackground:aStyleMask & CPHUDBackgroundWindowMask]; [self setMovableByWindowBackground:aStyleMask & CPHUDBackgroundWindowMask];
// Create a generic content view. // Create a generic content view.
[self setContentView:[[CPView alloc] initWithFrame:CGRectMakeZero()]]; [self setContentView:[[CPView alloc] initWithFrame:CGRectMakeZero()]];
_firstResponder = self; _firstResponder = self;
#if PLATFORM(DOM) #if PLATFORM(DOM)
_DOMElement = document.createElement("div"); _DOMElement = document.createElement("div");
_DOMElement.style.position = "absolute"; _DOMElement.style.position = "absolute";
_DOMElement.style.visibility = "visible"; _DOMElement.style.visibility = "visible";
_DOMElement.style.zIndex = 0; _DOMElement.style.zIndex = 0;
@@ -433,7 +441,7 @@ CPTexturedBackgroundWindowMask
[self setShowsResizeIndicator:_styleMask & CPResizableWindowMask]; [self setShowsResizeIndicator:_styleMask & CPResizableWindowMask];
} }
return self; return self;
} }
@@ -650,9 +658,10 @@ CPTexturedBackgroundWindowMask
if (shouldAnimate) if (shouldAnimate)
{ {
var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; [_frameAnimation stopAnimation];
_frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
[animation startAnimation];
[_frameAnimation startAnimation];
} }
else else
{ {
@@ -733,8 +742,10 @@ CPTexturedBackgroundWindowMask
*/ */
- (void)orderFront:(id)aSender - (void)orderFront:(id)aSender
{ {
#if PLATFORM(DOM)
[_platformWindow orderFront:self]; [_platformWindow orderFront:self];
[_platformWindow order:CPWindowAbove window:self relativeTo:nil]; [_platformWindow order:CPWindowAbove window:self relativeTo:nil];
#endif
if (_firstResponder === self || !_firstResponder) if (_firstResponder === self || !_firstResponder)
[self makeFirstResponder:[self initialFirstResponder]]; [self makeFirstResponder:[self initialFirstResponder]];
@@ -762,13 +773,17 @@ CPTexturedBackgroundWindowMask
*/ */
- (void)orderOut:(id)aSender - (void)orderOut:(id)aSender
{ {
#if PLATFORM(DOM)
if ([self _sharesChromeWithPlatformWindow]) if ([self _sharesChromeWithPlatformWindow])
[_platformWindow orderOut:self]; [_platformWindow orderOut:self];
#endif
if ([_delegate respondsToSelector:@selector(windowWillClose:)]) if ([_delegate respondsToSelector:@selector(windowWillClose:)])
[_delegate windowWillClose:self]; [_delegate windowWillClose:self];
#if PLATFORM(DOM)
[_platformWindow order:CPWindowOut window:self relativeTo:nil]; [_platformWindow order:CPWindowOut window:self relativeTo:nil];
#endif
[self _updateMainAndKeyWindows]; [self _updateMainAndKeyWindows];
} }
@@ -780,7 +795,9 @@ CPTexturedBackgroundWindowMask
*/ */
- (void)orderWindow:(CPWindowOrderingMode)aPlace relativeTo:(int)otherWindowNumber - (void)orderWindow:(CPWindowOrderingMode)aPlace relativeTo:(int)otherWindowNumber
{ {
#if PLATFORM(DOM)
[_platformWindow order:aPlace window:self relativeTo:CPApp._windows[otherWindowNumber]]; [_platformWindow order:aPlace window:self relativeTo:CPApp._windows[otherWindowNumber]];
#endif
} }
/*! /*!
@@ -865,12 +882,12 @@ CPTexturedBackgroundWindowMask
{ {
if (_contentView) if (_contentView)
[_contentView removeFromSuperview]; [_contentView removeFromSuperview];
var bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame)); var bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame));
_contentView = aView; _contentView = aView;
[_contentView setFrame:[self contentRectForFrameRect:bounds]]; [_contentView setFrame:[self contentRectForFrameRect:bounds]];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; [_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[_windowView addSubview:_contentView]; [_windowView addSubview:_contentView];
} }
@@ -883,6 +900,23 @@ CPTexturedBackgroundWindowMask
return _contentView; return _contentView;
} }
/*!
Applies an alpha value to the window.
@param aValue the alpha value to apply
*/
- (void)setAlphaValue:(float)aValue
{
[_windowView setAlphaValue:aValue];
}
/*!
Returns the alpha value of the window.
*/
- (float)alphaValue
{
return [_windowView alphaValue];
}
/*! /*!
Sets the window's background color. Sets the window's background color.
@param aColor the new color for the background @param aColor the new color for the background
@@ -909,24 +943,24 @@ CPTexturedBackgroundWindowMask
{ {
if (CGSizeEqualToSize(_minSize, aSize)) if (CGSizeEqualToSize(_minSize, aSize))
return; return;
_minSize = CGSizeCreateCopy(aSize); _minSize = CGSizeCreateCopy(aSize);
var size = CGSizeMakeCopy([self frame].size), var size = CGSizeMakeCopy([self frame].size),
needsFrameChange = NO; needsFrameChange = NO;
if (size.width < _minSize.width) if (size.width < _minSize.width)
{ {
size.width = _minSize.width; size.width = _minSize.width;
needsFrameChange = YES; needsFrameChange = YES;
} }
if (size.height < _minSize.height) if (size.height < _minSize.height)
{ {
size.height = _minSize.height; size.height = _minSize.height;
needsFrameChange = YES; needsFrameChange = YES;
} }
if (needsFrameChange) if (needsFrameChange)
[self setFrameSize:size]; [self setFrameSize:size];
} }
@@ -949,24 +983,24 @@ CPTexturedBackgroundWindowMask
{ {
if (CGSizeEqualToSize(_maxSize, aSize)) if (CGSizeEqualToSize(_maxSize, aSize))
return; return;
_maxSize = CGSizeCreateCopy(aSize); _maxSize = CGSizeCreateCopy(aSize);
var size = CGSizeMakeCopy([self frame].size), var size = CGSizeMakeCopy([self frame].size),
needsFrameChange = NO; needsFrameChange = NO;
if (size.width > _maxSize.width) if (size.width > _maxSize.width)
{ {
size.width = _maxSize.width; size.width = _maxSize.width;
needsFrameChange = YES; needsFrameChange = YES;
} }
if (size.height > _maxSize.height) if (size.height > _maxSize.height)
{ {
size.height = _maxSize.height; size.height = _maxSize.height;
needsFrameChange = YES; needsFrameChange = YES;
} }
if (needsFrameChange) if (needsFrameChange)
[self setFrameSize:size]; [self setFrameSize:size];
} }
@@ -1007,10 +1041,10 @@ CPTexturedBackgroundWindowMask
if (_hasShadow && !_shadowView) if (_hasShadow && !_shadowView)
{ {
var bounds = [_windowView bounds]; var bounds = [_windowView bounds];
_shadowView = [[CPView alloc] initWithFrame:CGRectMake(-SHADOW_MARGIN_LEFT, -SHADOW_MARGIN_TOP + SHADOW_DISTANCE, _shadowView = [[CPView alloc] initWithFrame:CGRectMake(-SHADOW_MARGIN_LEFT, -SHADOW_MARGIN_TOP + SHADOW_DISTANCE,
SHADOW_MARGIN_LEFT + CGRectGetWidth(bounds) + SHADOW_MARGIN_RIGHT, SHADOW_MARGIN_TOP + CGRectGetHeight(bounds) + SHADOW_MARGIN_BOTTOM)]; SHADOW_MARGIN_LEFT + CGRectGetWidth(bounds) + SHADOW_MARGIN_RIGHT, SHADOW_MARGIN_TOP + CGRectGetHeight(bounds) + SHADOW_MARGIN_BOTTOM)];
if (!_CPWindowShadowColor) if (!_CPWindowShadowColor)
{ {
var bundle = [CPBundle bundleForClass:[CPWindow class]]; var bundle = [CPBundle bundleForClass:[CPWindow class]];
@@ -1033,7 +1067,7 @@ CPTexturedBackgroundWindowMask
[_shadowView setBackgroundColor:_CPWindowShadowColor]; [_shadowView setBackgroundColor:_CPWindowShadowColor];
[_shadowView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; [_shadowView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
#if PLATFORM(DOM) #if PLATFORM(DOM)
CPDOMDisplayServerInsertBefore(_DOMElement, _shadowView._DOMElement, _windowView._DOMElement); CPDOMDisplayServerInsertBefore(_DOMElement, _shadowView._DOMElement, _windowView._DOMElement);
#endif #endif
@@ -1099,7 +1133,7 @@ CPTexturedBackgroundWindowMask
selector:@selector(windowDidBecomeKey:) selector:@selector(windowDidBecomeKey:)
name:CPWindowDidBecomeKeyNotification name:CPWindowDidBecomeKeyNotification
object:self]; object:self];
if ([_delegate respondsToSelector:@selector(windowDidBecomeMain:)]) if ([_delegate respondsToSelector:@selector(windowDidBecomeMain:)])
[defaultCenter [defaultCenter
addObserver:_delegate addObserver:_delegate
@@ -1195,7 +1229,7 @@ CPTexturedBackgroundWindowMask
if(!aResponder || ![aResponder acceptsFirstResponder] || ![aResponder becomeFirstResponder]) if(!aResponder || ![aResponder acceptsFirstResponder] || ![aResponder becomeFirstResponder])
{ {
_firstResponder = self; _firstResponder = self;
return NO; return NO;
} }
@@ -1248,9 +1282,9 @@ CPTexturedBackgroundWindowMask
- (void)setTitle:(CPString)aTitle - (void)setTitle:(CPString)aTitle
{ {
_title = aTitle; _title = aTitle;
[_windowView setTitle:aTitle]; [_windowView setTitle:aTitle];
[self _synchronizeMenuBarTitleWithWindowTitle]; [self _synchronizeMenuBarTitleWithWindowTitle];
} }
@@ -1325,10 +1359,21 @@ CPTexturedBackgroundWindowMask
*/ */
- (void)center - (void)center
{ {
if (_isFullPlatformWindow)
return;
var size = [self frame].size, var size = [self frame].size,
containerSize = [CPPlatform isBrowser] ? [_platformWindow contentBounds].size : [[self screen] visibleFrame].size; containerSize = [CPPlatform isBrowser] ? [_platformWindow contentBounds].size : [[self screen] visibleFrame].size;
[self setFrameOrigin:CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0)]; var origin = CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0);
if (origin.x < 0.0)
origin.x = 0.0;
if (origin.y < 0.0)
origin.y = 0.0;
[self setFrameOrigin:origin];
} }
/*! /*!
@@ -1342,8 +1387,37 @@ CPTexturedBackgroundWindowMask
switch (type) switch (type)
{ {
case CPFlagsChanged: return [[self firstResponder] flagsChanged:anEvent];
case CPKeyUp: return [[self firstResponder] keyUp:anEvent]; case CPKeyUp: return [[self firstResponder] keyUp:anEvent];
case CPKeyDown: return [[self firstResponder] keyDown:anEvent];
case CPKeyDown: if ([anEvent charactersIgnoringModifiers] === CPTabCharacter)
{
if ([anEvent modifierFlags] & CPShiftKeyMask)
[self selectPreviousKeyView:self];
else
[self selectNextKeyView:self];
return;
}
else if ([anEvent charactersIgnoringModifiers] === CPBackTabCharacter)
return [self selectPreviousKeyView:self];
[[self firstResponder] keyDown:anEvent];
// Trigger the default button if needed
// FIXME: Is this only applicable in a sheet? See isse: #722.
if (![self disableKeyEquivalentForDefaultButton])
{
var defaultButton = [self defaultButton],
keyEquivalent = [defaultButton keyEquivalent],
modifierMask = [defaultButton keyEquivalentModifierMask];
if ([anEvent _triggersKeyEquivalent:keyEquivalent withModifierMask:modifierMask])
[[self defaultButton] performClick:self];
}
return;
case CPScrollWheel: return [[_windowView hitTest:point] scrollWheel:anEvent]; case CPScrollWheel: return [[_windowView hitTest:point] scrollWheel:anEvent];
@@ -1502,7 +1576,7 @@ CPTexturedBackgroundWindowMask
- (void)makeKeyAndOrderFront:(id)aSender - (void)makeKeyAndOrderFront:(id)aSender
{ {
[self orderFront:self]; [self orderFront:self];
[self makeKeyWindow]; [self makeKeyWindow];
[self makeMainWindow]; [self makeMainWindow];
} }
@@ -1566,7 +1640,7 @@ CPTexturedBackgroundWindowMask
if (!pasteboardTypes) if (!pasteboardTypes)
return; return;
[_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes] [_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes];
if ([_inclusiveRegisteredDraggedTypes count] === 0) if ([_inclusiveRegisteredDraggedTypes count] === 0)
_inclusiveRegisteredDraggedTypes = nil; _inclusiveRegisteredDraggedTypes = nil;
@@ -1597,7 +1671,7 @@ CPTexturedBackgroundWindowMask
return; return;
[self _noteUnregisteredDraggedTypes:_registeredDraggedTypes]; [self _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
[_registeredDraggedTypes addObjectsFromArray:pasteboardTypes] [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes];
[self _noteRegisteredDraggedTypes:_registeredDraggedTypes]; [self _noteRegisteredDraggedTypes:_registeredDraggedTypes];
_registeredDraggedTypesArray = nil; _registeredDraggedTypesArray = nil;
@@ -1610,7 +1684,7 @@ CPTexturedBackgroundWindowMask
- (CPArray)registeredDraggedTypes - (CPArray)registeredDraggedTypes
{ {
if (!_registeredDraggedTypesArray) if (!_registeredDraggedTypesArray)
_registeredDraggedTypesArray = [_registeredDraggedTypes allObjects] _registeredDraggedTypesArray = [_registeredDraggedTypes allObjects];
return _registeredDraggedTypesArray; return _registeredDraggedTypesArray;
} }
@@ -1636,9 +1710,9 @@ CPTexturedBackgroundWindowMask
{ {
if (_isDocumentEdited == isDocumentEdited) if (_isDocumentEdited == isDocumentEdited)
return; return;
_isDocumentEdited = isDocumentEdited; _isDocumentEdited = isDocumentEdited;
[CPMenu _setMenuBarIconImageAlphaValue:_isDocumentEdited ? 0.5 : 1.0]; [CPMenu _setMenuBarIconImageAlphaValue:_isDocumentEdited ? 0.5 : 1.0];
[_windowView setDocumentEdited:isDocumentEdited]; [_windowView setDocumentEdited:isDocumentEdited];
@@ -1656,11 +1730,11 @@ CPTexturedBackgroundWindowMask
{ {
if (_isDocumentSaving == isDocumentSaving) if (_isDocumentSaving == isDocumentSaving)
return; return;
_isDocumentSaving = isDocumentSaving; _isDocumentSaving = isDocumentSaving;
[self _synchronizeSaveMenuWithDocumentSaving]; [self _synchronizeSaveMenuWithDocumentSaving];
[_windowView windowDidChangeDocumentSaving]; [_windowView windowDidChangeDocumentSaving];
} }
@@ -1677,16 +1751,16 @@ CPTexturedBackgroundWindowMask
var mainMenu = [CPApp mainMenu], var mainMenu = [CPApp mainMenu],
index = [mainMenu indexOfItemWithTitle:_isDocumentSaving ? @"Save" : @"Saving..."]; index = [mainMenu indexOfItemWithTitle:_isDocumentSaving ? @"Save" : @"Saving..."];
if (index == CPNotFound) if (index == CPNotFound)
return; return;
var item = [mainMenu itemAtIndex:index]; var item = [mainMenu itemAtIndex:index];
if (_isDocumentSaving) if (_isDocumentSaving)
{ {
CPWindowSaveImage = [item image]; CPWindowSaveImage = [item image];
[item setTitle:@"Saving..."]; [item setTitle:@"Saving..."];
[item setImage:CPWindowSavingImage]; [item setImage:CPWindowSavingImage];
[item setEnabled:NO]; [item setEnabled:NO];
@@ -1776,7 +1850,7 @@ CPTexturedBackgroundWindowMask
if (![_delegate windowShouldClose:self]) if (![_delegate windowShouldClose:self])
return; return;
} }
// Only check self is delegate does NOT implement this. This also ensures this when delegate == self (returns true). // Only check self is delegate does NOT implement this. This also ensures this when delegate == self (returns true).
else if ([self respondsToSelector:@selector(windowShouldClose:)] && ![self windowShouldClose:self]) else if ([self respondsToSelector:@selector(windowShouldClose:)] && ![self windowShouldClose:self])
return; return;
@@ -1786,8 +1860,8 @@ CPTexturedBackgroundWindowMask
{ {
var index = [documents indexOfObject:[_windowController document]]; var index = [documents indexOfObject:[_windowController document]];
[documents[index] shouldCloseWindowController:_windowController [documents[index] shouldCloseWindowController:_windowController
delegate:self delegate:self
shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:) shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:)
contextInfo:{documents:[documents copy], visited:0, index:index}]; contextInfo:{documents:[documents copy], visited:0, index:index}];
} }
@@ -1811,8 +1885,8 @@ CPTexturedBackgroundWindowMask
{ {
[windowController setDocument:documents[index]]; [windowController setDocument:documents[index]];
[documents[index] shouldCloseWindowController:_windowController [documents[index] shouldCloseWindowController:_windowController
delegate:self delegate:self
shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:) shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:)
contextInfo:context]; contextInfo:context];
} }
@@ -1849,7 +1923,7 @@ CPTexturedBackgroundWindowMask
// FIXME: Also check if we can resize and titlebar. // FIXME: Also check if we can resize and titlebar.
if ([self isVisible]) if ([self isVisible])
return YES; return YES;
return NO; return NO;
} }
@@ -1907,10 +1981,17 @@ CPTexturedBackgroundWindowMask
[keyWindow makeKeyWindow]; [keyWindow makeKeyWindow];
else else
{ {
var menuWindow = [CPApp mainMenu]._menuWindow; var mainMenu = [CPApp mainMenu],
menuBarClass = objj_getClass("_CPMenuBarWindow"),
menuWindow;
for (var i = 0; i < windowCount; i++) for (var i = 0; i < windowCount; i++)
{ {
var currentWindow = allWindows[i]; var currentWindow = allWindows[i];
if ([currentWindow isKindOfClass:menuBarClass])
menuWindow = currentWindow;
if (currentWindow === self || currentWindow === menuWindow) if (currentWindow === self || currentWindow === menuWindow)
continue; continue;
@@ -1935,10 +2016,17 @@ CPTexturedBackgroundWindowMask
[mainWindow makeMainWindow]; [mainWindow makeMainWindow];
else else
{ {
var menuWindow = [CPApp mainMenu]._menuWindow; var mainMenu = [CPApp mainMenu],
menuBarClass = objj_getClass("_CPMenuBarWindow"),
menuWindow;
for (var i = 0; i < windowCount; i++) for (var i = 0; i < windowCount; i++)
{ {
var currentWindow = allWindows[i]; var currentWindow = allWindows[i];
if ([currentWindow isKindOfClass:menuBarClass])
menuWindow = currentWindow;
if (currentWindow === self || currentWindow === menuWindow) if (currentWindow === self || currentWindow === menuWindow)
continue; continue;
@@ -1969,25 +2057,25 @@ CPTexturedBackgroundWindowMask
{ {
if (_toolbar === aToolbar) if (_toolbar === aToolbar)
return; return;
// If this has an owner, dump it! // If this has an owner, dump it!
[[aToolbar _window] setToolbar:nil]; [[aToolbar _window] setToolbar:nil];
// This is no longer out toolbar. // This is no longer out toolbar.
[_toolbar _setWindow:nil]; [_toolbar _setWindow:nil];
_toolbar = aToolbar; _toolbar = aToolbar;
// THIS is our toolbar. // THIS is our toolbar.
[_toolbar _setWindow:self]; [_toolbar _setWindow:self];
[self _noteToolbarChanged]; [self _noteToolbarChanged];
} }
- (void)toggleToolbarShown:(id)aSender - (void)toggleToolbarShown:(id)aSender
{ {
var toolbar = [self toolbar]; var toolbar = [self toolbar];
[toolbar setVisible:![toolbar isVisible]]; [toolbar setVisible:![toolbar isVisible]];
} }
@@ -2003,10 +2091,10 @@ CPTexturedBackgroundWindowMask
else else
{ {
newFrame = CGRectMakeCopy([self frame]); newFrame = CGRectMakeCopy([self frame]);
newFrame.origin = frame.origin; newFrame.origin = frame.origin;
} }
[self setFrame:newFrame]; [self setFrame:newFrame];
/* /*
[_windowView setAnimatingToolbar:YES]; [_windowView setAnimatingToolbar:YES];
@@ -2018,11 +2106,17 @@ CPTexturedBackgroundWindowMask
- (void)_setFrame:(CGRect)aFrame delegate:(id)delegate duration:(int)duration curve:(CPAnimationCurve)curve - (void)_setFrame:(CGRect)aFrame delegate:(id)delegate duration:(int)duration curve:(CPAnimationCurve)curve
{ {
var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; [_frameAnimation stopAnimation];
[animation setDelegate:delegate]; _frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
[animation setAnimationCurve:curve]; [_frameAnimation setDelegate:delegate];
[animation setDuration:duration]; [_frameAnimation setAnimationCurve:curve];
[animation startAnimation]; [_frameAnimation setDuration:duration];
[_frameAnimation startAnimation];
}
- (CPTimeInterval)animationResizeTime:(CGRect)newWindowFrame
{
return CPWindowResizeTime;
} }
/* @ignore */ /* @ignore */
@@ -2032,7 +2126,7 @@ CPTexturedBackgroundWindowMask
var attachedSheet = [self attachedSheet]; var attachedSheet = [self attachedSheet];
var contentRect = [[self contentView] frame], var contentRect = [[self contentView] frame],
sheetFrame = CGRectMakeCopy([attachedSheet frame]); sheetFrame = CGRectMakeCopy([attachedSheet frame]);
sheetFrame.origin.y = CGRectGetMinY(_frame) + CGRectGetMinY(contentRect); sheetFrame.origin.y = CGRectGetMinY(_frame) + CGRectGetMinY(contentRect);
sheetFrame.origin.x = CGRectGetMinX(_frame) + FLOOR((CGRectGetWidth(_frame) - CGRectGetWidth(sheetFrame)) / 2.0); sheetFrame.origin.x = CGRectGetMinX(_frame) + FLOOR((CGRectGetWidth(_frame) - CGRectGetWidth(sheetFrame)) / 2.0);
@@ -2044,8 +2138,8 @@ CPTexturedBackgroundWindowMask
{ {
var sheetFrame = [aSheet frame]; var sheetFrame = [aSheet frame];
_sheetContext = {"sheet":aSheet, "modalDelegate":aModalDelegate, "endSelector":aDidEndSelector, "contextInfo":aContextInfo, "frame":CGRectMakeCopy(sheetFrame), "returnCode":-1, "opened": NO}; _sheetContext = {"sheet":aSheet, "modalDelegate":aModalDelegate, "endSelector":aDidEndSelector, "contextInfo":aContextInfo, "frame":CGRectMakeCopy(sheetFrame), "returnCode":-1, "opened": NO};
[self _attachSheetWindow:aSheet]; [self _attachSheetWindow:aSheet];
} }
@@ -2055,12 +2149,12 @@ CPTexturedBackgroundWindowMask
var sheetFrame = [aSheet frame], var sheetFrame = [aSheet frame],
frame = [self frame], frame = [self frame],
sheetContent = [aSheet contentView]; sheetContent = [aSheet contentView];
[self _setUpMasksForView:sheetContent]; [self _setUpMasksForView:sheetContent];
aSheet._isSheet = YES; aSheet._isSheet = YES;
aSheet._parentView = self; aSheet._parentView = self;
var originx = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width)/2), var originx = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width)/2),
originy = frame.origin.y + [[self contentView] frame].origin.y, originy = frame.origin.y + [[self contentView] frame].origin.y,
startFrame = CGRectMake(originx, originy, sheetFrame.size.width, 0), startFrame = CGRectMake(originx, originy, sheetFrame.size.width, 0),
@@ -2068,15 +2162,15 @@ CPTexturedBackgroundWindowMask
[[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillBeginSheetNotification object:self]; [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillBeginSheetNotification object:self];
[CPApp runModalForWindow:aSheet]; [CPApp runModalForWindow:aSheet];
[aSheet orderFront:self]; [aSheet orderFront:self];
[aSheet setFrame:startFrame display:YES animate:NO]; [aSheet setFrame:startFrame display:YES animate:NO];
_sheetContext["opened"] = YES; _sheetContext["opened"] = YES;
[aSheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseOut]; [aSheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseOut];
// Should run the main loop here until _isAnimating = FALSE // Should run the main loop here until _isAnimating = FALSE
[aSheet becomeKeyWindow]; [aSheet becomeKeyWindow];
} }
/* @ignore */ /* @ignore */
@@ -2087,14 +2181,14 @@ CPTexturedBackgroundWindowMask
endFrame = CGRectMakeCopy(startFrame); endFrame = CGRectMakeCopy(startFrame);
endFrame.size.height = 0; endFrame.size.height = 0;
_sheetContext["frame"] = startFrame; _sheetContext["frame"] = startFrame;
var sheetContent = [sheet contentView]; var sheetContent = [sheet contentView];
[self _setUpMasksForView:sheetContent]; [self _setUpMasksForView:sheetContent];
_sheetContext["opened"] = NO; _sheetContext["opened"] = NO;
[sheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseIn]; [sheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseIn];
} }
/* @ignore */ /* @ignore */
@@ -2105,31 +2199,33 @@ CPTexturedBackgroundWindowMask
return; return;
var sheetContent = [sheet contentView]; var sheetContent = [sheet contentView];
if (_sheetContext["opened"] === YES) if (_sheetContext["opened"] === YES)
{ {
[self _restoreMasksForView:sheetContent]; [self _restoreMasksForView:sheetContent];
return; return;
} }
[CPApp stopModal]; [CPApp stopModal];
[[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidEndSheetNotification object:self]; [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidEndSheetNotification object:self];
[sheet orderOut:self]; [sheet orderOut:self];
var lastFrame = _sheetContext["frame"]; var lastFrame = _sheetContext["frame"];
[sheet setFrame:lastFrame]; [sheet setFrame:lastFrame];
[self _restoreMasksForView:sheetContent]; [self _restoreMasksForView:sheetContent];
var delegate = _sheetContext["modalDelegate"], var delegate = _sheetContext["modalDelegate"],
endSelector = _sheetContext["endSelector"]; endSelector = _sheetContext["endSelector"],
returnCode = _sheetContext["returnCode"],
if (delegate != nil && endSelector != nil) contextInfo = _sheetContext["contextInfo"];
objj_msgSend(delegate, endSelector, sheet, _sheetContext["returnCode"], _sheetContext["contextInfo"]);
_sheetContext = nil; _sheetContext = nil;
sheet._parentView = nil; sheet._parentView = nil;
if (delegate != nil && endSelector != nil)
objj_msgSend(delegate, endSelector, sheet, returnCode, contextInfo);
} }
- (void)_setUpMasksForView:(CPView)aView - (void)_setUpMasksForView:(CPView)aView
@@ -2137,7 +2233,7 @@ CPTexturedBackgroundWindowMask
var views = [aView subviews]; var views = [aView subviews];
[views addObject:aView]; [views addObject:aView];
for (var i = 0, count = [views count]; i < count; i++) for (var i = 0, count = [views count]; i < count; i++)
{ {
var view = [views objectAtIndex:i], var view = [views objectAtIndex:i],
@@ -2153,7 +2249,7 @@ CPTexturedBackgroundWindowMask
var views = [aView subviews]; var views = [aView subviews];
[views addObject:aView]; [views addObject:aView];
for (var i = 0, count = [views count]; i < count; i++) for (var i = 0, count = [views count]; i < count; i++)
{ {
var view = [views objectAtIndex:i], var view = [views objectAtIndex:i],
@@ -2171,7 +2267,7 @@ CPTexturedBackgroundWindowMask
{ {
if (_sheetContext === nil) if (_sheetContext === nil)
return nil; return nil;
return _sheetContext["sheet"]; return _sheetContext["sheet"];
} }
@@ -2202,7 +2298,7 @@ CPTexturedBackgroundWindowMask
return NO; return NO;
} }
- (void)performKeyEquivalent:(CPEvent)anEvent - (BOOL)performKeyEquivalent:(CPEvent)anEvent
{ {
// FIXME: should we be starting at the root, in other words _windowView? // FIXME: should we be starting at the root, in other words _windowView?
// The evidence seems to point to no... // The evidence seems to point to no...
@@ -2213,19 +2309,92 @@ CPTexturedBackgroundWindowMask
{ {
// It's not clear why we do performKeyEquivalent again here... // It's not clear why we do performKeyEquivalent again here...
// Perhaps to allow something to happen between sendEvent: and keyDown:? // Perhaps to allow something to happen between sendEvent: and keyDown:?
if (![anEvent _couldBeKeyEquivalent] || ![self performKeyEquivalent:anEvent]) if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent])
[self interpretKeyEvents:[anEvent]]; return;
// Apple's documentation is inconsistent with their behavior here. According to the docs
// an event going of the responder chain is passed to the input system as a last resort.
// However, the only methods I could get Cocoa to call automatically are
// moveUp: moveDown: moveLeft: moveRight: pageUp: pageDown: and complete:
[self _processKeyboardUIKey:anEvent];
} }
- (void)insertNewline:(id)sender /*
@ignore
Interprets the key event for action messages and sends the action message down the responder chain
Cocoa only sends moveDown:, moveUp:, moveLeft:, moveRight:, pageUp:, pageDown: and complete: messages.
We deviate from this by sending (the default) scrollPageUp: scrollPageDown: for pageUp and pageDown keys.
@param anEvent the event to handle.
@return YES if the key event was handled, NO if no responder handled the key event
*/
- (BOOL)_processKeyboardUIKey:(CPEvent)anEvent
{ {
if (_defaultButton && _defaultButtonEnabled) var character = [anEvent charactersIgnoringModifiers],
[_defaultButton performClick:nil]; uiKeys = [CPLeftArrowFunctionKey, CPRightArrowFunctionKey, CPUpArrowFunctionKey, CPDownArrowFunctionKey, CPPageUpFunctionKey, CPPageDownFunctionKey, CPEscapeFunctionKey];
if (![uiKeys containsObject:character])
return NO;
var selectors = [CPKeyBinding selectorsForKey:character modifierFlags:0];
if ([selectors count] <= 0)
return NO;
if (character !== CPEscapeFunctionKey)
{
var selector = [selectors objectAtIndex:0];
return [[self firstResponder] tryToPerform:selector with:self];
}
else
{
// Cocoa sends complete: for the escape key (in stead of the default cancelOperation:)
// This is also the only action that is not sent directly to the first responder, but through doCommandBySelector.
// The difference is that doCommandBySelector: will also send the action to the window and application delegates.
[[self firstResponder] doCommandBySelector:@selector(complete:)];
}
} }
- (void)insertTab:(id)sender /*
@ignore
Interprets the key event for action messages and sends the action message down the responder chain
Cocoa only sends moveDown:, moveUp:, moveLeft:, moveRight:, pageUp:, pageDown: and complete: messages.
We deviate from this by sending (the default) scrollPageUp: scrollPageDown: for pageUp and pageDown keys.
@param anEvent the event to handle.
@return YES if the key event was handled, NO if no responder handled the key event
*/
- (BOOL)_processKeyboardUIKey:(CPEvent)anEvent
{ {
[self selectNextKeyView:nil]; var character = [anEvent charactersIgnoringModifiers],
uiKeys = [
CPLeftArrowFunctionKey,
CPRightArrowFunctionKey,
CPUpArrowFunctionKey,
CPDownArrowFunctionKey,
CPPageUpFunctionKey,
CPPageDownFunctionKey,
CPEscapeFunctionKey
];
if (![uiKeys containsObject:character])
return NO;
var selectors = [CPKeyBinding selectorsForKey:character modifierFlags:0];
if ([selectors count] <= 0)
return NO;
if (character !== CPEscapeFunctionKey)
{
var selector = [selectors objectAtIndex:0];
return [[self firstResponder] tryToPerform:selector with:self];
}
else
{
// Cocoa sends complete: for the escape key (in stead of the default cancelOperation:)
// This is also the only action that is not sent directly to the first responder, but through doCommandBySelector.
// The difference is that doCommandBySelector: will also send the action to the window and application delegates.
[[self firstResponder] doCommandBySelector:@selector(complete:)];
}
} }
- (void)_dirtyKeyViewLoop - (void)_dirtyKeyViewLoop
@@ -2252,7 +2421,7 @@ CPTexturedBackgroundWindowMask
- (void)recalculateKeyViewLoop - (void)recalculateKeyViewLoop
{ {
var subviews = []; var subviews = [];
[self _appendSubviewsOf:_contentView toArray:subviews]; [self _appendSubviewsOf:_contentView toArray:subviews];
var keyViewOrder = [subviews sortedArrayUsingFunction:keyViewComparator context:_contentView], var keyViewOrder = [subviews sortedArrayUsingFunction:keyViewComparator context:_contentView],
@@ -2260,7 +2429,7 @@ CPTexturedBackgroundWindowMask
for (var i=0; i<count; i++) for (var i=0; i<count; i++)
[keyViewOrder[i] setNextKeyView:keyViewOrder[(i+1)%count]]; [keyViewOrder[i] setNextKeyView:keyViewOrder[(i+1)%count]];
_keyViewLoopIsDirty = NO; _keyViewLoopIsDirty = NO;
} }
@@ -2281,7 +2450,7 @@ CPTexturedBackgroundWindowMask
return; return;
_autorecalculatesKeyViewLoop = shouldRecalculate; _autorecalculatesKeyViewLoop = shouldRecalculate;
if (_keyViewLoopIsDirty) if (_keyViewLoopIsDirty)
[self recalculateKeyViewLoop]; [self recalculateKeyViewLoop];
else if (_autorecalculatesKeyViewLoop) else if (_autorecalculatesKeyViewLoop)
@@ -2333,11 +2502,16 @@ CPTexturedBackgroundWindowMask
- (void)setDefaultButton:(CPButton)aButton - (void)setDefaultButton:(CPButton)aButton
{ {
[_defaultButton setDefaultButton:NO]; if (_defaultButton === aButton)
return;
if ([_defaultButton keyEquivalent] === CPCarriageReturnCharacter)
[_defaultButton setKeyEquivalent:nil];
_defaultButton = aButton; _defaultButton = aButton;
[_defaultButton setDefaultButton:YES]; if ([_defaultButton keyEquivalent] !== CPCarriageReturnCharacter)
[_defaultButton setKeyEquivalent:CPCarriageReturnCharacter];
} }
- (CPButton)defaultButton - (CPButton)defaultButton
@@ -2404,7 +2578,7 @@ var keyViewComparator = function(a, b, context)
{ {
if ([self isFullPlatformWindow]) if ([self isFullPlatformWindow])
return [self setFrame:[_platformWindow visibleFrame]]; return [self setFrame:[_platformWindow visibleFrame]];
if (_autoresizingMask == CPWindowNotSizable) if (_autoresizingMask == CPWindowNotSizable)
return; return;
@@ -2419,7 +2593,7 @@ var keyViewComparator = function(a, b, context)
newFrame.origin.x += dX; newFrame.origin.x += dX;
if (_autoresizingMask & CPWindowWidthSizable) if (_autoresizingMask & CPWindowWidthSizable)
newFrame.size.width += dX; newFrame.size.width += dX;
if (_autoresizingMask & CPWindowMinYMargin) if (_autoresizingMask & CPWindowMinYMargin)
newFrame.origin.y += dY; newFrame.origin.y += dY;
if (_autoresizingMask & CPWindowHeightSizable) if (_autoresizingMask & CPWindowHeightSizable)
@@ -2591,39 +2765,39 @@ var interpolate = function(fromValue, toValue, progress)
@implementation _CPWindowFrameAnimation : CPAnimation @implementation _CPWindowFrameAnimation : CPAnimation
{ {
CPWindow _window; CPWindow _window;
CGRect _startFrame; CGRect _startFrame;
CGRect _targetFrame; CGRect _targetFrame;
} }
- (id)initWithWindow:(CPWindow)aWindow targetFrame:(CGRect)aTargetFrame - (id)initWithWindow:(CPWindow)aWindow targetFrame:(CGRect)aTargetFrame
{ {
self = [super initWithDuration:0.2 animationCurve:CPAnimationLinear]; self = [super initWithDuration:[aWindow animationResizeTime:aTargetFrame] animationCurve:CPAnimationLinear];
if (self) if (self)
{ {
_window = aWindow; _window = aWindow;
_targetFrame = CGRectMakeCopy(aTargetFrame); _targetFrame = CGRectMakeCopy(aTargetFrame);
_startFrame = CGRectMakeCopy([_window frame]); _startFrame = CGRectMakeCopy([_window frame]);
} }
return self; return self;
} }
- (void)startAnimation - (void)startAnimation
{ {
[super startAnimation]; [super startAnimation];
_window._isAnimating = YES; _window._isAnimating = YES;
} }
- (void)setCurrentProgress:(float)aProgress - (void)setCurrentProgress:(float)aProgress
{ {
[super setCurrentProgress:aProgress]; [super setCurrentProgress:aProgress];
var value = [self currentValue]; var value = [self currentValue];
if (value == 1.0) if (value == 1.0)
_window._isAnimating = NO; _window._isAnimating = NO;
+12 -12
View File
@@ -43,21 +43,21 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
_CPHUDWindowViewBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices: _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/CPWindowHUDBackground0.png"] size:CPSizeMake(7.0, 37.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground1.png"] size:CPSizeMake(1.0, 78.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(6.0, 78.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/CPWindowHUDBackground3.png"] size:CPSizeMake(7.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/CPWindowHUDBackground4.png"] size:CPSizeMake(2.0, 2.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(6.0, 1.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/CPWindowHUDBackground6.png"] size:CPSizeMake(7.0, 3.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground7.png"] size:CPSizeMake(6.0, 6.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(6.0, 6.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)]; _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(20.0, 20.0)]; _CPHUDWindowViewCloseActiveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowCloseActive.png"] size:CPSizeMake(18.0, 18.0)];
} }
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect + (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
@@ -148,7 +148,7 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
{ {
var closeSize = [_CPHUDWindowViewCloseImage size]; 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]; [_closeButton setBordered:NO];
+1
View File
@@ -22,6 +22,7 @@
@import "_CPWindowView.j" @import "_CPWindowView.j"
var GRADIENT_HEIGHT = 41.0; var GRADIENT_HEIGHT = 41.0;
var _CPTexturedWindowHeadGradientColor = nil, var _CPTexturedWindowHeadGradientColor = nil,
+1 -3
View File
@@ -20,10 +20,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CPView.j"
@import "CPImageView.j" @import "CPImageView.j"
@import "CPView.j"
#include "../CoreGraphics/CGGeometry.h"
var _CPWindowViewResizeIndicatorImage = nil; var _CPWindowViewResizeIndicatorImage = nil;
+2 -4
View File
@@ -27,8 +27,6 @@
@import "CPWindow.j" @import "CPWindow.j"
@import "CPDocument.j" @import "CPDocument.j"
#include "Platform/Platform.h"
/*! /*!
@ingroup appkit @ingroup appkit
@@ -133,7 +131,7 @@
if (_window) if (_window)
return; 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]];
} }
/*! /*!
@@ -424,7 +422,7 @@
if (_windowCibPath) if (_windowCibPath)
return _windowCibPath; return _windowCibPath;
return [[CPBundle bundleForClass:[_cibOwner class]] pathForResource:_windowCibName + @".cib"]; return [[CPBundle mainBundle] pathForResource:_windowCibName + @".cib"];
} }
// Setting and Getting Window Attributes // Setting and Getting Window Attributes
+1 -1
View File
@@ -150,7 +150,7 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
var topLevelObjects = [anExternalNameTable objectForKey:CPCibTopLevelObjects]; var topLevelObjects = [anExternalNameTable objectForKey:CPCibTopLevelObjects];
[objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects] [objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects];
[objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects]; [objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects];
[objectData awakeWithOwner:owner topLevelObjects:topLevelObjects]; [objectData awakeWithOwner:owner topLevelObjects:topLevelObjects];
+9 -3
View File
@@ -39,9 +39,11 @@
// Not having a selector is a fatal error. // Not having a selector is a fatal error.
if (!selector) if (!selector)
{
[CPException [CPException
raise:CPInvalidArgumentException raise:CPInvalidArgumentException
reason:@"-[" + [self className] + ' ' + _cmd + @"] selector " + selectorName + @" does not exist."]; reason:@"-[" + [self className] + ' ' + _cmd + @"] selector " + selectorName + @" does not exist."];
}
// If the destination doesn't respond to this selector, warn but don't die. // If the destination doesn't respond to this selector, warn but don't die.
if (_destination && ![_destination respondsToSelector:selector]) if (_destination && ![_destination respondsToSelector:selector])
@@ -58,7 +60,7 @@
else else
[CPException [CPException
raise:CPInvalidArgumentException 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. // Not being able to set the target is a fatal error.
if ([_source respondsToSelector:@selector(setTarget:)]) if ([_source respondsToSelector:@selector(setTarget:)])
@@ -67,10 +69,14 @@
else else
[CPException [CPException
raise:CPInvalidArgumentException 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 @end
@implementation _CPCibControlConnector : CPCibControlConnector { } @end @implementation _CPCibControlConnector : CPCibControlConnector
{
}
@end
+14 -14
View File
@@ -37,12 +37,12 @@ var CPCibOwner = @"CPCibOwner";
@implementation CPBundle (CPCibLoading) @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"]) if (![aName hasSuffix:@".cib"])
aName = [aName stringByAppendingString:@".cib"]; aName = [aName stringByAppendingString:@".cib"];
@@ -51,24 +51,24 @@ var CPCibOwner = @"CPCibOwner";
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle], var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
path = [bundle pathForResource:aName]; 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 initWithContentsOfURL:anAbsolutePath
loadDelegate:[[_CPCibLoadDelegate alloc] loadDelegate:[[_CPCibLoadDelegate alloc]
initWithLoadDelegate:aDelegate 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"]) if (![aName hasSuffix:@".cib"])
aName = [aName stringByAppendingString:@".cib"]; aName = [aName stringByAppendingString:@".cib"];
@@ -77,17 +77,17 @@ var CPCibOwner = @"CPCibOwner";
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle], var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
path = [bundle pathForResource:aName]; 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 initWithCibNamed:aFileName
bundle:self bundle:self
loadDelegate:[[_CPCibLoadDelegate alloc] loadDelegate:[[_CPCibLoadDelegate alloc]
initWithLoadDelegate:aDelegate initWithLoadDelegate:aDelegate
externalNameTable:aNameTable]]; externalNameTable:aNameTable]]);
} }
@end @end
+15 -5
View File
@@ -46,28 +46,28 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
- (id)initWithClassName:(CPString)aClassName resourceName:(CPString)aResourceName properties:(CPDictionary)properties - (id)initWithClassName:(CPString)aClassName resourceName:(CPString)aResourceName properties:(CPDictionary)properties
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_className = aClassName; _className = aClassName;
_resourceName = aResourceName; _resourceName = aResourceName;
_properties = properties; _properties = properties;
} }
return self; return self;
} }
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_className = [aCoder decodeObjectForKey:_CPCibCustomResourceClassNameKey]; _className = [aCoder decodeObjectForKey:_CPCibCustomResourceClassNameKey];
_resourceName = [aCoder decodeObjectForKey:_CPCibCustomResourceResourceNameKey]; _resourceName = [aCoder decodeObjectForKey:_CPCibCustomResourceResourceNameKey];
_properties = [aCoder decodeObjectForKey:_CPCibCustomResourcePropertiesKey]; _properties = [aCoder decodeObjectForKey:_CPCibCustomResourcePropertiesKey];
} }
return self; return self;
} }
@@ -80,7 +80,7 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
- (id)awakeAfterUsingCoder:(CPCoder)aCoder - (id)awakeAfterUsingCoder:(CPCoder)aCoder
{ {
if ([aCoder respondsToSelector:@selector(bundle)] && if ([aCoder respondsToSelector:@selector(bundle)] &&
(![aCoder respondsToSelector:@selector(awakenCustomResources)] || [aCoder awakenCustomResources])) (![aCoder respondsToSelector:@selector(awakenCustomResources)] || [aCoder awakenCustomResources]))
if (_className === @"CPImage") if (_className === @"CPImage")
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:_properties.valueForKey(@"size")]; return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:_properties.valueForKey(@"size")];
@@ -112,4 +112,14 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
return NO; return NO;
} }
- (unsigned)loadStatus
{
return CPImageLoadStatusCompleted;
}
- (id)delegate
{
return nil;
}
@end @end
+3
View File
@@ -1,6 +1,9 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import "CGGeometry.j"
@import "CPWindow.j"
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey", var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey", _CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
+3 -6
View File
@@ -22,13 +22,10 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import <AppKit/CABackingStore.j> @import "CABackingStore.j"
@import <AppKit/CGContext.j> @import "CGContext.j"
@import <AppKit/CGGeometry.j> @import "CGGeometry.j"
#include "../CoreGraphics/CGGeometry.h"
#include "../CoreGraphics/CGAffineTransform.j"
#define DOM(aLayer) aLayer._DOMElement #define DOM(aLayer) aLayer._DOMElement
+2 -5
View File
@@ -20,14 +20,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 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" @import "CGGeometry.j"
#define _function(inline) function inline { return _##inline; }
_function(CGAffineTransformMake(a, b, c, d, tx, ty)) _function(CGAffineTransformMake(a, b, c, d, tx, ty))
_function(CGAffineTransformMakeIdentity()) _function(CGAffineTransformMakeIdentity())
_function(CGAffineTransformMakeCopy(anAffineTransform)) _function(CGAffineTransformMakeCopy(anAffineTransform))
+3 -4
View File
@@ -20,13 +20,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 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 "CGAffineTransform.j"
@import "CPCompatibility.j"
@import "CGGeometry.j"
@import "CGPath.j" @import "CGPath.j"
kCGLineCapButt = 0; kCGLineCapButt = 0;
kCGLineCapRound = 1; kCGLineCapRound = 1;
kCGLineCapSquare = 2; kCGLineCapSquare = 2;
+1
View File
@@ -63,6 +63,7 @@
#define _CGInsetMakeCopy(anInset) _CGInsetMake(anInset.top, anInset.right, anInset.bottom, anInset.left) #define _CGInsetMakeCopy(anInset) _CGInsetMake(anInset.top, anInset.right, anInset.bottom, anInset.left)
#define _CGInsetMakeZero() _CGInsetMake(0, 0, 0, 0) #define _CGInsetMakeZero() _CGInsetMake(0, 0, 0, 0)
#define _CGInsetIsEmpty(anInset) ((anInset).top === 0 && (anInset).right === 0 && (anInset).bottom === 0 && (anInset).left === 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 // DEPRECATED
#define _CGPointCreateCopy(aPoint) _CGPointMake(aPoint.x, aPoint.y) #define _CGPointCreateCopy(aPoint) _CGPointMake(aPoint.x, aPoint.y)
+65 -17
View File
@@ -20,8 +20,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "CGGeometry.h"
#define _function(inline) function inline { return _##inline; } #define _function(inline) function inline { return _##inline; }
_function(CGPointMake(x, y)) _function(CGPointMake(x, y))
@@ -69,6 +67,12 @@ _function(CGInsetMake(top, right, bottom, left))
_function(CGInsetMakeZero()) _function(CGInsetMakeZero())
_function(CGInsetMakeCopy(anInset)) _function(CGInsetMakeCopy(anInset))
_function(CGInsetIsEmpty(anInset)) _function(CGInsetIsEmpty(anInset))
_function(CGInsetEqualToInset(lhsInset, rhsInset))
CGMinXEdge = 0;
CGMinYEdge = 1;
CGMaxXEdge = 2;
CGMaxYEdge = 3;
CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 0.0); CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 0.0);
@@ -77,6 +81,50 @@ CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 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, must not be the same object, and must not be the
same object as inRect.
@group CGRect
*/
function CGRectDivide(inRect, slice, rem, amount, edge)
{
slice.origin = _CGPointMakeCopy(inRect.origin);
slice.size = _CGSizeMakeCopy(inRect.size);
rem.origin = _CGPointMakeCopy(inRect.origin);
rem.size = _CGSizeMakeCopy(inRect.size);
switch (edge)
{
case CGMinXEdge:
slice.size.width = amount;
rem.origin.x += amount;
rem.size.width -= amount;
break;
case CGMaxXEdge:
slice.origin.x = _CGRectGetMaxX(slice) - amount;
slice.size.width = amount;
rem.size.width -= amount;
break;
case CGMinYEdge:
slice.size.height = amount;
rem.origin.y += amount;
rem.size.height -= amount;
break;
case CGMaxYEdge:
slice.origin.y = _CGRectGetMaxY(slice) - amount;
slice.size.height = amount;
rem.size.height -= amount;
}
}
/*! /*!
Returns a \c BOOL indicating whether CGRect \c lhsRect Returns a \c BOOL indicating whether CGRect \c lhsRect
contains CGRect \c rhsRect. contains CGRect \c rhsRect.
@@ -88,7 +136,7 @@ CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 0.0);
function CGRectContainsRect(lhsRect, rhsRect) function CGRectContainsRect(lhsRect, rhsRect)
{ {
var union = CGRectUnion(lhsRect, rhsRect); var union = CGRectUnion(lhsRect, rhsRect);
return _CGRectEqualToRect(union, lhsRect); return _CGRectEqualToRect(union, lhsRect);
} }
@@ -102,12 +150,12 @@ function CGRectContainsRect(lhsRect, rhsRect)
function CGRectIntersectsRect(lhsRect, rhsRect) function CGRectIntersectsRect(lhsRect, rhsRect)
{ {
var intersection = CGRectIntersection(lhsRect, rhsRect); var intersection = CGRectIntersection(lhsRect, rhsRect);
return !_CGRectIsEmpty(intersection); return !_CGRectIsEmpty(intersection);
} }
/*! /*!
Makes the origin and size of a CGRect all integers. Specifically, by making Makes the origin and size of a CGRect all integers. Specifically, by making
the southwest corner the origin (rounded down), and the northeast corner a CGSize (rounded up). the southwest corner the origin (rounded down), and the northeast corner a CGSize (rounded up).
@param aRect the rectangle to operate on @param aRect the rectangle to operate on
@return CGRect the modified rectangle (same as the input) @return CGRect the modified rectangle (same as the input)
@@ -120,7 +168,7 @@ function CGRectIntegral(aRect)
// Store these out separately, if not the GetMaxes will return incorrect values. // Store these out separately, if not the GetMaxes will return incorrect values.
var x = FLOOR(_CGRectGetMinX(aRect)), var x = FLOOR(_CGRectGetMinX(aRect)),
y = FLOOR(_CGRectGetMinY(aRect)); y = FLOOR(_CGRectGetMinY(aRect));
aRect.size.width = CEIL(_CGRectGetMaxX(aRect)) - x; aRect.size.width = CEIL(_CGRectGetMaxX(aRect)) - x;
aRect.size.height = CEIL(_CGRectGetMaxY(aRect)) - y; aRect.size.height = CEIL(_CGRectGetMaxY(aRect)) - y;
@@ -140,18 +188,18 @@ function CGRectIntegral(aRect)
function CGRectIntersection(lhsRect, rhsRect) function CGRectIntersection(lhsRect, rhsRect)
{ {
var intersection = _CGRectMake( var intersection = _CGRectMake(
MAX(_CGRectGetMinX(lhsRect), _CGRectGetMinX(rhsRect)), MAX(_CGRectGetMinX(lhsRect), _CGRectGetMinX(rhsRect)),
MAX(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)), MAX(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)),
0, 0); 0, 0);
intersection.size.width = MIN(_CGRectGetMaxX(lhsRect), _CGRectGetMaxX(rhsRect)) - _CGRectGetMinX(intersection); intersection.size.width = MIN(_CGRectGetMaxX(lhsRect), _CGRectGetMaxX(rhsRect)) - _CGRectGetMinX(intersection);
intersection.size.height = MIN(_CGRectGetMaxY(lhsRect), _CGRectGetMaxY(rhsRect)) - _CGRectGetMinY(intersection); intersection.size.height = MIN(_CGRectGetMaxY(lhsRect), _CGRectGetMaxY(rhsRect)) - _CGRectGetMinY(intersection);
return _CGRectIsEmpty(intersection) ? _CGRectMakeZero() : intersection; return _CGRectIsEmpty(intersection) ? _CGRectMakeZero() : intersection;
} }
/* /*
*/ */
function CGRectStandardize(aRect) function CGRectStandardize(aRect)
{ {
@@ -189,28 +237,28 @@ function CGRectUnion(lhsRect, rhsRect)
minY = MIN(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)), minY = MIN(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)),
maxX = MAX(_CGRectGetMaxX(lhsRect), _CGRectGetMaxX(rhsRect)), maxX = MAX(_CGRectGetMaxX(lhsRect), _CGRectGetMaxX(rhsRect)),
maxY = MAX(_CGRectGetMaxY(lhsRect), _CGRectGetMaxY(rhsRect)); maxY = MAX(_CGRectGetMaxY(lhsRect), _CGRectGetMaxY(rhsRect));
return _CGRectMake(minX, minY, maxX - minX, maxY - minY); return _CGRectMake(minX, minY, maxX - minX, maxY - minY);
} }
function CGPointFromString(aString) function CGPointFromString(aString)
{ {
var comma = aString.indexOf(','); var comma = aString.indexOf(',');
return { x:parseInt(aString.substr(1, comma - 1)), y:parseInt(aString.substring(comma + 1, aString.length)) }; return { x:parseInt(aString.substr(1, comma - 1)), y:parseInt(aString.substring(comma + 1, aString.length)) };
} }
function CGSizeFromString(aString) function CGSizeFromString(aString)
{ {
var comma = aString.indexOf(','); var comma = aString.indexOf(',');
return { width:parseInt(aString.substr(1, comma - 1)), height:parseInt(aString.substring(comma + 1, aString.length)) }; return { width:parseInt(aString.substr(1, comma - 1)), height:parseInt(aString.substring(comma + 1, aString.length)) };
} }
function CGRectFromString(aString) function CGRectFromString(aString)
{ {
var comma = aString.indexOf(',', aString.indexOf(',') + 1); var comma = aString.indexOf(',', aString.indexOf(',') + 1);
return { origin:CGPointFromString(aString.substr(1, comma - 1)), size:CGSizeFromString(aString.substring(comma + 2, aString.length)) }; return { origin:CGPointFromString(aString.substr(1, comma - 1)), size:CGSizeFromString(aString.substring(comma + 2, aString.length)) };
} }
@@ -233,6 +281,6 @@ function CPStringFromCGInset(anInset)
return '{' + anInset.top + ", " + anInset.left + ", " + anInset.bottom + ", " + anInset.right + '}'; return '{' + anInset.top + ", " + anInset.left + ", " + anInset.bottom + ", " + anInset.right + '}';
} }
/*! /*!
@} @}
*/ */

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