Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c288930a3c | ||
|
|
596676a562 | ||
|
|
cc3d9f337c | ||
|
|
8d210100a5 | ||
|
|
d25e96902f | ||
|
|
ad792d9772 | ||
|
|
9e7b737960 | ||
|
|
9bc6a69b76 | ||
|
|
1cb28e4206 | ||
|
|
5311689265 | ||
|
|
4228a2a146 | ||
|
|
bacc50c271 | ||
|
|
9f459f053e | ||
|
|
4195f3b8c6 | ||
|
|
4926824482 | ||
|
|
cb2f539cf7 | ||
|
|
7f31be7cb1 | ||
|
|
78b9c5b576 | ||
|
|
01e35efdbb | ||
|
|
bef1687b1f | ||
|
|
da18a9eb24 | ||
|
|
d975e90407 | ||
|
|
abc8e14275 | ||
|
|
b032cd5b7d | ||
|
|
bb589285e3 | ||
|
|
1d52c3e957 | ||
|
|
df5ce9e0f3 | ||
|
|
16b446ae08 | ||
|
|
d0a5b6e1c7 | ||
|
|
271a1ef3b4 | ||
|
|
b91042eb08 | ||
|
|
608cb86a4a | ||
|
|
88780ff0a9 | ||
|
|
a5e241afd7 | ||
|
|
28772d3254 | ||
|
|
d1f5c1eebc | ||
|
|
d40ebaf369 | ||
|
|
06f74e5ef0 | ||
|
|
5eaeb5f05e | ||
|
|
961cb2f6ed | ||
|
|
4dca2bbb85 | ||
|
|
892d3d7120 | ||
|
|
c0fe499937 | ||
|
|
01e8e9e597 | ||
|
|
08b740c36f | ||
|
|
31918bc0cd | ||
|
|
d45aeed224 | ||
|
|
7d2835c522 | ||
|
|
c77a282aaf | ||
|
|
7a1cd5c545 | ||
|
|
cff26bd4e6 | ||
|
|
936ae1d563 | ||
|
|
3d52935be0 | ||
|
|
777b167a2a | ||
|
|
c5d602bd6d | ||
|
|
8545195cd7 | ||
|
|
74fd73c18d | ||
|
|
2479f15b6b | ||
|
|
75875f4032 | ||
|
|
0752b63b03 | ||
|
|
bde2f20fa3 | ||
|
|
29ff54054e | ||
|
|
8e1bbe0132 | ||
|
|
c12305f40a | ||
|
|
2be149c486 | ||
|
|
a2b6585c0d | ||
|
|
c7a16deb6f | ||
|
|
aa452952a8 | ||
|
|
1fb8c95b5d | ||
|
|
6ea4aa0a66 | ||
|
|
ad630c840b | ||
|
|
16b52035c1 | ||
|
|
e98cd9e069 | ||
|
|
e99f7261f3 | ||
|
|
85b370e6cf | ||
|
|
2462cd7b1d | ||
|
|
331e338c06 | ||
|
|
2b68f40872 | ||
|
|
2f7b3c306d | ||
|
|
eba5dbe654 | ||
|
|
9ae1f548bf | ||
|
|
c5ab90ae52 | ||
|
|
776cdf93fe | ||
|
|
2bbba19aba | ||
|
|
635a57b036 | ||
|
|
5b231867dc | ||
|
|
d191255a84 | ||
|
|
9bf8824109 | ||
|
|
f773bd217c | ||
|
|
a5f0f0e3db | ||
|
|
6f6bfc667b | ||
|
|
0789f49b94 | ||
|
|
92c94eab8f | ||
|
|
9f06ed725e | ||
|
|
6eee5543f9 | ||
|
|
c45039fd70 | ||
|
|
8e203ec78e | ||
|
|
1918528710 | ||
|
|
e32515e5cc | ||
|
|
2b77da821c | ||
|
|
f8404c7a97 | ||
|
|
b007f9899d | ||
|
|
156610ee07 | ||
|
|
8a460b65ed | ||
|
|
fcaf672bf8 | ||
|
|
dd5d8fcdce | ||
|
|
e0c4f6455d | ||
|
|
dd5d7e9979 | ||
|
|
408baac91e | ||
|
|
f241142216 | ||
|
|
f0561844d8 | ||
|
|
bd6294b806 | ||
|
|
70f8e3a832 | ||
|
|
59b302acde | ||
|
|
f54f8dfec9 | ||
|
|
93135e7e81 | ||
|
|
b8026e19ba | ||
|
|
147d9282fb | ||
|
|
7c18b8bc5f | ||
|
|
2ccbf5d4e5 | ||
|
|
da6d8c86d1 | ||
|
|
78d997b404 | ||
|
|
8fa12b874e | ||
|
|
a9edc868f1 | ||
|
|
c6e5219f2e | ||
|
|
3bb450adbf | ||
|
|
a0f5257258 | ||
|
|
6520615bb0 | ||
|
|
4593212698 | ||
|
|
5363deb122 | ||
|
|
d5a651fc43 | ||
|
|
4740acbcc6 | ||
|
|
bfb2134329 | ||
|
|
ec83977fe1 | ||
|
|
98d08ff05d | ||
|
|
1eb6319b49 | ||
|
|
8f7e06f9d6 | ||
|
|
81e3abe10c | ||
|
|
edcee8934d | ||
|
|
d115d2ef47 | ||
|
|
d1dd725848 | ||
|
|
ebdba33082 | ||
|
|
7e465689e4 | ||
|
|
918f6fbb8f | ||
|
|
1cab9463ad | ||
|
|
3974a483d1 | ||
|
|
28733ec592 | ||
|
|
916b9a399b | ||
|
|
3d62791477 | ||
|
|
64e6764015 | ||
|
|
ecf8f7b143 | ||
|
|
cbed5c9cb1 | ||
|
|
0246d501e2 | ||
|
|
3d5b30ab9e | ||
|
|
4719578f10 | ||
|
|
fe370c7066 | ||
|
|
63d208bf20 | ||
|
|
5158540208 | ||
|
|
a69f7dc81a | ||
|
|
e848e161d4 | ||
|
|
3db61216e1 | ||
|
|
63b00186f4 | ||
|
|
110d4c478d | ||
|
|
49c29ded92 | ||
|
|
06670f2214 | ||
|
|
134bfec615 | ||
|
|
279326ffe1 | ||
|
|
ecb04e983e | ||
|
|
73b4c33f05 | ||
|
|
ad30f4dcbb | ||
|
|
0318587f80 | ||
|
|
2b6fddf26c | ||
|
|
f57755ce46 | ||
|
|
da61da392b | ||
|
|
984b46ba07 | ||
|
|
1abce77b3a | ||
|
|
eaa51835ef | ||
|
|
9038b7cfa9 | ||
|
|
420606d8e8 | ||
|
|
80c8fd9794 | ||
|
|
1f479c3f20 | ||
|
|
0af89853d4 | ||
|
|
b5bb9c8ec3 | ||
|
|
ff13de9f75 | ||
|
|
47f40eb04b | ||
|
|
8dd174d1e3 | ||
|
|
1ffc7ed6fb | ||
|
|
b9b0eb79d8 | ||
|
|
a5832aa66b | ||
|
|
63710d5fae | ||
|
|
9472f76ad5 | ||
|
|
a2ef701d18 | ||
|
|
55e07536d9 | ||
|
|
4da5669ecb | ||
|
|
c232680600 | ||
|
|
bd25b6fb48 | ||
|
|
834d878a4d | ||
|
|
4cb5ccbc3a | ||
|
|
929cd78bae | ||
|
|
af0a479f88 | ||
|
|
86a28d8cc1 | ||
|
|
3dd178a69d | ||
|
|
417334419a | ||
|
|
c03b3c2d34 | ||
|
|
e97d4a8e72 | ||
|
|
24d0af3104 | ||
|
|
5790e99359 | ||
|
|
0d6c2c9890 | ||
|
|
f5961b9e06 | ||
|
|
7fb17e9f41 | ||
|
|
42220e057b | ||
|
|
c5df9c973f | ||
|
|
91509e7d36 | ||
|
|
dd70bdc698 | ||
|
|
59d619d190 | ||
|
|
dd160d6bed | ||
|
|
ae5a2c4164 | ||
|
|
a939bed8e0 | ||
|
|
b89aa9af0d | ||
|
|
c686a4384b | ||
|
|
6bb2dd2a16 | ||
|
|
4421b55613 | ||
|
|
75d9929483 | ||
|
|
7c78c2ef5d | ||
|
|
3758c86d20 | ||
|
|
ada547a79d | ||
|
|
2ec574173a | ||
|
|
743feb5360 | ||
|
|
bc4dc041e5 | ||
|
|
8c8d1ae3d3 | ||
|
|
445adcb47f | ||
|
|
4e9b975ca8 | ||
|
|
5d26066e02 | ||
|
|
de73d86684 | ||
|
|
d6244f090e | ||
|
|
a9781016be | ||
|
|
4be0bb3a30 | ||
|
|
a74267e937 | ||
|
|
6dea853ef3 | ||
|
|
94df530580 | ||
|
|
d038c50531 | ||
|
|
83546d58db | ||
|
|
8de587d4fc | ||
|
|
bd9a6ea150 | ||
|
|
fe69142567 | ||
|
|
1c44dc1052 | ||
|
|
5f85f7bef1 | ||
|
|
4f7fbdc344 | ||
|
|
397e314cc9 | ||
|
|
c87d96676c | ||
|
|
c5f37e665b | ||
|
|
13d4e36d39 | ||
|
|
a5c06c8f27 | ||
|
|
76bdbb660e | ||
|
|
99180ba001 | ||
|
|
a7929e6c1e | ||
|
|
9377cf9128 | ||
|
|
e17d8ca302 | ||
|
|
b3cbc7e362 | ||
|
|
d6b3efaae8 | ||
|
|
acbaa1eec4 | ||
|
|
33345f65ce | ||
|
|
65b6ff6ecc | ||
|
|
3fe5ec5d6d | ||
|
|
142b982577 | ||
|
|
147c65b962 | ||
|
|
df7aa30267 | ||
|
|
0f4aab926e | ||
|
|
7f3512d22c | ||
|
|
a6b5ed22b0 | ||
|
|
e843b31287 | ||
|
|
06a5aa45ba | ||
|
|
45a5eed62f | ||
|
|
188e27e931 | ||
|
|
89dbccd74e | ||
|
|
ed560ed489 | ||
|
|
186eb66f52 | ||
|
|
a4647f2b82 | ||
|
|
94336ebcbb | ||
|
|
5dfa43ce5f | ||
|
|
ff7774976e | ||
|
|
a435e54a67 | ||
|
|
852597f11d | ||
|
|
806fea9222 | ||
|
|
972bb4100f | ||
|
|
6a6b83635f | ||
|
|
d8f202fc1f | ||
|
|
2322743252 | ||
|
|
8b3f9c5557 | ||
|
|
b573daf59b | ||
|
|
4f8fa778d5 | ||
|
|
30d5a7f7a2 | ||
|
|
b01a4436b6 | ||
|
|
9ad8f75a08 | ||
|
|
2bf9afa97a | ||
|
|
9e892d4eea | ||
|
|
d2407d1c2a | ||
|
|
17dc96ad2f | ||
|
|
b3a427ba18 | ||
|
|
4cdefcc2c7 | ||
|
|
b7c0dcf050 | ||
|
|
fe9573e5b8 | ||
|
|
9fcf0258e0 | ||
|
|
e22faa0d79 | ||
|
|
175b204bb6 | ||
|
|
b126b2946d | ||
|
|
fec200c835 | ||
|
|
ea0a47a845 | ||
|
|
835d89774a | ||
|
|
f0a2a91837 | ||
|
|
8614bab724 | ||
|
|
9c181cc9c9 | ||
|
|
a0a7b126ab | ||
|
|
8b566f06f0 | ||
|
|
78ddc2db70 | ||
|
|
28d174d9d8 | ||
|
|
dd892f746d | ||
|
|
95b1b8b19d | ||
|
|
298b73ddfc | ||
|
|
e80cbc89b2 | ||
|
|
c0f5ed1f87 | ||
|
|
51a8975f0a | ||
|
|
4b9695ff50 | ||
|
|
a02b721944 | ||
|
|
f60a92d2c4 |
@@ -9,3 +9,4 @@ WebSite
|
||||
*.xcodeproj/*.perspectivev3
|
||||
xcuserdata/
|
||||
!*.xcodeproj/project.pbxproj
|
||||
target
|
||||
|
||||
@@ -37,12 +37,14 @@
|
||||
@import "CPCibControlConnector.j"
|
||||
@import "CPCibLoading.j"
|
||||
@import "CPCibOutletConnector.j"
|
||||
@import "CPCibRuntimeAttributesConnector.j"
|
||||
@import "CPClipView.j"
|
||||
@import "CPCollectionView.j"
|
||||
@import "CPCollectionViewItem.j"
|
||||
@import "CPColor.j"
|
||||
@import "CPColorPanel.j"
|
||||
@import "CPColorWell.j"
|
||||
@import "CPComboBox.j"
|
||||
@import "CPCompatibility.j"
|
||||
@import "CPControl.j"
|
||||
@import "CPCookie.j"
|
||||
@@ -66,6 +68,7 @@
|
||||
@import "CPOutlineView.j"
|
||||
@import "CPPanel.j"
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPPopover.j"
|
||||
@import "CPPopUpButton.j"
|
||||
@import "CPPredicateEditor.j"
|
||||
@import "CPPredicateEditorRowTemplate.j"
|
||||
|
||||
@@ -117,7 +117,7 @@ CPCriticalAlertStyle = 2;
|
||||
*/
|
||||
+ (CPAlert)alertWithMessageText:(CPString)aMessage defaultButton:(CPString)defaultButtonTitle alternateButton:(CPString)alternateButtonTitle otherButton:(CPString)otherButtonTitle informativeTextWithFormat:(CPString)informativeText
|
||||
{
|
||||
var alert = [[CPAlert alloc] init];
|
||||
var alert = [[self alloc] init];
|
||||
|
||||
[alert setMessageText:aMessage];
|
||||
[alert addButtonWithTitle:defaultButtonTitle];
|
||||
@@ -142,7 +142,7 @@ CPCriticalAlertStyle = 2;
|
||||
*/
|
||||
+ (CPAlert)alertWithError:(CPString)anErrorMessage
|
||||
{
|
||||
var alert = [[CPAlert alloc] init];
|
||||
var alert = [[self alloc] init];
|
||||
|
||||
[alert setMessageText:anErrorMessage];
|
||||
[alert setAlertStyle:CPCriticalAlertStyle];
|
||||
|
||||
@@ -306,6 +306,9 @@ ACTUAL_FRAME_RATE = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
|
||||
return [_delegate animation:self valueForProgress:t];
|
||||
|
||||
if (_animationCurve == CPAnimationLinear)
|
||||
return t;
|
||||
|
||||
var c1 = [],
|
||||
c2 = [];
|
||||
|
||||
@@ -107,7 +107,7 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
CPPanel _aboutPanel;
|
||||
|
||||
CPThemeBlend _themeBlend @accessors(property=themeBlend);
|
||||
CPArray _themeBlends @accessors(property=themeBlends);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -141,6 +141,8 @@ CPRunContinuesResponse = -1002;
|
||||
_windows = [];
|
||||
|
||||
[_windows addObject:nil];
|
||||
|
||||
_themeBlends = [];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -338,7 +340,7 @@ CPRunContinuesResponse = -1002;
|
||||
Copyright - Human readable copyright information.
|
||||
</pre>
|
||||
|
||||
If you choose not the include any of the above keys, they will default
|
||||
If you choose not the include any of the above keys, they will default
|
||||
to the following respective keys in your info.plist file.
|
||||
|
||||
<pre>
|
||||
@@ -1003,7 +1005,7 @@ CPRunContinuesResponse = -1002;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the arguments of your application.
|
||||
Sets the arguments of your application.
|
||||
That is, set the slash seperated values of an array as the window location hash.
|
||||
|
||||
For example if you pass an array:
|
||||
@@ -1156,6 +1158,16 @@ CPRunContinuesResponse = -1002;
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
- (CPThemeBlend)themeBlend
|
||||
{
|
||||
return (_themeBlends.length > 0 ? _themeBlends[0] : nil);
|
||||
}
|
||||
|
||||
- (void)setThemeBlend:(CPThemeBlend)aThemeBlend
|
||||
{
|
||||
_themeBlends[0] = aThemeBlend;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeName
|
||||
{
|
||||
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
|
||||
@@ -1218,15 +1230,14 @@ function CPApplicationMain(args, namedArgs)
|
||||
[_CPAppBootstrapper performActions];
|
||||
}
|
||||
|
||||
var _CPAppBootstrapperActions = nil;
|
||||
var _CPAppBootstrapperActions = nil,
|
||||
_CPAppThemeURLsToLoad = [];
|
||||
|
||||
@implementation _CPAppBootstrapper : CPObject
|
||||
{
|
||||
}
|
||||
|
||||
+ (CPArray)actions
|
||||
{
|
||||
return [@selector(bootstrapPlatform), @selector(loadDefaultTheme), @selector(loadMainCibFile)];
|
||||
return [@selector(bootstrapPlatform), @selector(loadThemes), @selector(loadMainCibFile)];
|
||||
}
|
||||
|
||||
+ (void)performActions
|
||||
@@ -1250,17 +1261,30 @@ var _CPAppBootstrapperActions = nil;
|
||||
return [CPPlatform bootstrap];
|
||||
}
|
||||
|
||||
+ (BOOL)loadDefaultTheme
|
||||
+ (BOOL)loadThemes
|
||||
{
|
||||
var defaultThemeName = [CPApplication defaultThemeName],
|
||||
themeURL = nil;
|
||||
_CPAppThemeURLsToLoad.push([CPApplication defaultThemeName]);
|
||||
|
||||
if (defaultThemeName === @"Aristo")
|
||||
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:defaultThemeName + @".blend"];
|
||||
var auxiliaryThemes = ([[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPAuxiliaryThemes"] || []);
|
||||
|
||||
_CPAppThemeURLsToLoad = _CPAppThemeURLsToLoad.concat(auxiliaryThemes);
|
||||
|
||||
[self loadNextTheme];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (BOOL)loadNextTheme
|
||||
{
|
||||
var themeName = _CPAppThemeURLsToLoad.shift();
|
||||
|
||||
if (themeName === @"Aristo")
|
||||
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:themeName + @".blend"];
|
||||
else
|
||||
themeURL = [[CPBundle mainBundle] pathForResource:defaultThemeName + @".blend"];
|
||||
themeURL = [[CPBundle mainBundle] pathForResource:themeName + @".blend"];
|
||||
|
||||
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:themeURL];
|
||||
|
||||
[blend loadWithDelegate:self];
|
||||
|
||||
return YES;
|
||||
@@ -1268,10 +1292,17 @@ var _CPAppBootstrapperActions = nil;
|
||||
|
||||
+ (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend
|
||||
{
|
||||
[[CPApplication sharedApplication] setThemeBlend:aThemeBlend];
|
||||
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
|
||||
var themeBlends = [CPApp themeBlends];
|
||||
|
||||
[self performActions];
|
||||
[themeBlends addObject:aThemeBlend];
|
||||
|
||||
if ([themeBlends count] === 1)
|
||||
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
|
||||
|
||||
if (_CPAppThemeURLsToLoad.length === 0)
|
||||
[self performActions];
|
||||
else
|
||||
[self loadNextTheme];
|
||||
}
|
||||
|
||||
+ (BOOL)loadMainCibFile
|
||||
|
||||
@@ -564,8 +564,9 @@
|
||||
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
|
||||
{
|
||||
[self _selectionWillChange]
|
||||
[self __setSelectionIndexes:indexes];
|
||||
var r = [self __setSelectionIndexes:indexes];
|
||||
[self _selectionDidChange];
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -574,7 +575,7 @@
|
||||
*/
|
||||
- (BOOL)__setSelectionIndex:(int)theIndex
|
||||
{
|
||||
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:theIndex]];
|
||||
return [self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:theIndex]];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -583,28 +584,38 @@
|
||||
*/
|
||||
- (BOOL)__setSelectionIndexes:(CPIndexSet)indexes
|
||||
{
|
||||
if (!indexes)
|
||||
indexes = [CPIndexSet indexSet];
|
||||
var newIndexes = indexes;
|
||||
|
||||
if (![indexes count])
|
||||
if (!newIndexes)
|
||||
newIndexes = [CPIndexSet indexSet];
|
||||
|
||||
if (![newIndexes count])
|
||||
{
|
||||
if (_avoidsEmptySelection && [[self arrangedObjects] count])
|
||||
indexes = [CPIndexSet indexSetWithIndex:0];
|
||||
newIndexes = [CPIndexSet indexSetWithIndex:0];
|
||||
}
|
||||
else
|
||||
{
|
||||
var objectsCount = [[self arrangedObjects] count];
|
||||
|
||||
// Don't trash the input - the caller might depend on it or we might have been
|
||||
// given _selectionIndexes as the input in which case the equality test below
|
||||
// would always succeed despite our change below.
|
||||
newIndexes = [newIndexes copy];
|
||||
|
||||
// Remove out of bounds indexes.
|
||||
[indexes removeIndexesInRange:CPMakeRange(objectsCount, [indexes lastIndex] + 1)];
|
||||
[newIndexes removeIndexesInRange:CPMakeRange(objectsCount, [newIndexes 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 (![newIndexes count] && _avoidsEmptySelection && objectsCount)
|
||||
newIndexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
|
||||
}
|
||||
|
||||
if ([_selectionIndexes isEqualToIndexSet:indexes])
|
||||
if ([_selectionIndexes isEqualToIndexSet:newIndexes])
|
||||
return NO;
|
||||
|
||||
_selectionIndexes = [indexes copy];
|
||||
// If we haven't already created our own index instance, make sure to copy it here so that
|
||||
// the copy the user sent in is decoupled from our internal copy.
|
||||
_selectionIndexes = indexes === newIndexes ? [indexes copy] : newIndexes;
|
||||
|
||||
// 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.
|
||||
@@ -636,10 +647,11 @@
|
||||
[self willChangeValueForKey:@"selectionIndexes"];
|
||||
[self _selectionWillChange];
|
||||
|
||||
[self __setSelectedObjects:objects];
|
||||
var r = [self __setSelectedObjects:objects];
|
||||
|
||||
[self didChangeValueForKey:@"selectionIndexes"];
|
||||
[self _selectionDidChange];
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -61,6 +61,7 @@ CPGrooveBorder = 3;
|
||||
var box = [[self alloc] initWithFrame:CGRectMakeZero()],
|
||||
enclosingView = [aView superview];
|
||||
|
||||
[box setAutoresizingMask:[aView autoresizingMask]];
|
||||
[box setFrameFromContentFrame:[aView frame]];
|
||||
|
||||
[enclosingView replaceSubview:aView with:box];
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
@import "CPCompatibility.j"
|
||||
@import "CPImage.j"
|
||||
|
||||
/// @cond IGNORE
|
||||
|
||||
var _redComponent = 0,
|
||||
_greenComponent = 1,
|
||||
@@ -54,6 +55,66 @@ var cachedBlackColor,
|
||||
cachedShadowColor,
|
||||
cachedClearColor;
|
||||
|
||||
/// @endcond
|
||||
|
||||
/*!
|
||||
Orientation to use with \c CPColorPattern for vertical patterns.
|
||||
*/
|
||||
CPColorPatternIsVertical = YES,
|
||||
|
||||
/*!
|
||||
Orientation to use with \c CPColorPattern for horizontal patterns.
|
||||
*/
|
||||
CPColorPatternIsHorizontal = NO;
|
||||
|
||||
/*!
|
||||
To create a simple color with a pattern image:
|
||||
|
||||
<code>CPColorWithImages(name, width, height{, bundle})</code>
|
||||
|
||||
To create a color with a three part pattern image:
|
||||
|
||||
<code>CPColorWithImages(slices{, orientation})</code>
|
||||
|
||||
where slices is an array of three [name, width, height{, bundle}] arrays,
|
||||
and orientation is \c CPColorPatternIsVertical or \ref CPColorPatternIsHorizontal.
|
||||
If orientatation is not passed, it defaults to \ref CPColorPatternIsHorizontal.
|
||||
|
||||
To create a color with a nine part pattern image:
|
||||
|
||||
<code>CPColorWithImages(slices);</code>
|
||||
|
||||
where slices is an array of nine [name, width, height{, bundle}] arrays.
|
||||
*/
|
||||
function CPColorWithImages()
|
||||
{
|
||||
if (arguments.length < 3)
|
||||
{
|
||||
var slices = arguments[0],
|
||||
imageSlices = [];
|
||||
|
||||
for (var i = 0; i < slices.length; ++i)
|
||||
{
|
||||
var slice = slices[i];
|
||||
|
||||
imageSlices.push(slice ? CPImageInBundle(slice[0], CGSizeMake(slice[1], slice[2]), slice[3]) : nil);
|
||||
}
|
||||
|
||||
if (imageSlices.length === 3)
|
||||
return [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:imageSlices isVertical:arguments[1] || CPColorPatternIsHorizontal]];
|
||||
else
|
||||
return [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:imageSlices]];
|
||||
}
|
||||
else if (arguments.length === 3 || arguments.length === 4)
|
||||
{
|
||||
return [CPColor colorWithPatternImage:CPImageInBundle(arguments[0], CGSizeMake(arguments[1], arguments[2]), arguments[3])];
|
||||
}
|
||||
else
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
@@ -633,7 +694,36 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [super description]+" "+[self cssString];
|
||||
var description = [super description],
|
||||
patternImage = [self patternImage];
|
||||
|
||||
if (!patternImage)
|
||||
return description + " " + [self cssString];
|
||||
|
||||
description += " {\n";
|
||||
|
||||
if ([patternImage isThreePartImage] || [patternImage isNinePartImage])
|
||||
{
|
||||
var slices = [patternImage imageSlices];
|
||||
|
||||
if ([patternImage isThreePartImage])
|
||||
description += " orientation: " + ([patternImage isVertical] ? "vertical" : "horizontal") + ",\n";
|
||||
|
||||
description += " patternImage (" + slices.length + " part): [\n";
|
||||
|
||||
for (var i = 0; i < slices.length; ++i)
|
||||
{
|
||||
var imgDescription = [slices[i] description];
|
||||
|
||||
description += imgDescription.replace(/^/mg, " ") + ",\n";
|
||||
}
|
||||
|
||||
description = description.substr(0, description.length - 2) + "\n ]\n}";
|
||||
}
|
||||
else
|
||||
description += [patternImage description].replace(/^/mg, " ") + "\n}";
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -678,8 +768,10 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
||||
|
||||
@end
|
||||
|
||||
/// @cond IGNORE
|
||||
var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
CPColorPatternImageKey = @"CPColorPatternImageKey";
|
||||
/// @endcond
|
||||
|
||||
@implementation CPColor (CPCoding)
|
||||
|
||||
@@ -710,13 +802,12 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
@end
|
||||
|
||||
|
||||
/// @cond IGNORE
|
||||
var hexCharacters = "0123456789ABCDEF";
|
||||
|
||||
/*!
|
||||
Used for the CPColor \c +colorWithHexString: implementation
|
||||
@ignore
|
||||
@class CPColor
|
||||
@return an array of rgb components
|
||||
/*
|
||||
Used for the CPColor +colorWithHexString: implementation.
|
||||
Returns an array of rgb components.
|
||||
*/
|
||||
var hexToRGB = function(hex)
|
||||
{
|
||||
@@ -754,3 +845,5 @@ var byteToHex = function(n)
|
||||
return hexCharacters.charAt((n - n % 16) / 16) +
|
||||
hexCharacters.charAt(n % 16);
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#import "../Foundation/Ref.h"
|
||||
|
||||
@import "../Foundation/CPFormatter.j"
|
||||
@import "CPFont.j"
|
||||
@import "CPShadow.j"
|
||||
@import "CPView.j"
|
||||
@@ -82,6 +85,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
@implementation CPControl : CPView
|
||||
{
|
||||
id _value;
|
||||
CPFormatter _formatter @accessors(property=formatter);
|
||||
|
||||
// Target-Action Support
|
||||
id _target;
|
||||
@@ -221,10 +225,11 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
@param anAction the action to send
|
||||
@param anObject the object to which the action will be sent
|
||||
*/
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
- (BOOL)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
[self _reverseSetBinding];
|
||||
[CPApp sendAction:anAction to:anObject from:self];
|
||||
|
||||
return [CPApp sendAction:anAction to:anObject from:self];
|
||||
}
|
||||
|
||||
- (int)sendActionOn:(int)mask
|
||||
@@ -502,15 +507,46 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
*/
|
||||
- (CPString)stringValue
|
||||
{
|
||||
if (_formatter && _value !== undefined && _value !== nil)
|
||||
{
|
||||
var formattedValue = [self hasThemeState:CPThemeStateEditing] ? [_formatter editingStringForObjectValue:_value] : [_formatter stringForObjectValue:_value];
|
||||
|
||||
if (formattedValue !== nil && formattedValue !== undefined)
|
||||
return formattedValue;
|
||||
}
|
||||
|
||||
return (_value === undefined || _value === nil) ? "" : String(_value);
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the receiver's string value.
|
||||
*/
|
||||
- (void)setStringValue:(CPString)anObject
|
||||
- (void)setStringValue:(CPString)aString
|
||||
{
|
||||
[self setObjectValue:anObject];
|
||||
// Cocoa raises an invalid parameter assertion and returns if you pass nil.
|
||||
if (aString === nil || aString === undefined)
|
||||
{
|
||||
CPLog.warn("nil or undefined sent to CPControl -setStringValue");
|
||||
return;
|
||||
}
|
||||
|
||||
var value;
|
||||
|
||||
if (_formatter)
|
||||
{
|
||||
value = nil;
|
||||
|
||||
if (![_formatter getObjectValue:AT_REF(value) forString:aString errorDescription:nil])
|
||||
{
|
||||
// If the given string is non-empty and doesn't work, Cocoa tries an empty string.
|
||||
if (!aString || ![_formatter getObjectValue:AT_REF(value) forString:@"" errorDescription:nil])
|
||||
value = undefined; // Means the value is invalid
|
||||
}
|
||||
}
|
||||
else
|
||||
value = aString;
|
||||
|
||||
[self setObjectValue:value];
|
||||
}
|
||||
|
||||
- (void)takeDoubleValueFrom:(id)sender
|
||||
@@ -526,21 +562,18 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
[self setFloatValue:[sender floatValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void)takeIntegerValueFrom:(id)sender
|
||||
{
|
||||
if ([sender respondsToSelector:@selector(integerValue)])
|
||||
[self setIntegerValue:[sender integerValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void)takeIntValueFrom:(id)sender
|
||||
{
|
||||
if ([sender respondsToSelector:@selector(intValue)])
|
||||
[self setIntValue:[sender intValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void)takeObjectValueFrom:(id)sender
|
||||
{
|
||||
if ([sender respondsToSelector:@selector(objectValue)])
|
||||
@@ -882,7 +915,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
||||
if (_target !== nil)
|
||||
[aCoder encodeConditionalObject:_target forKey:CPControlTargetKey];
|
||||
|
||||
if (_action !== NULL)
|
||||
if (_action !== nil)
|
||||
[aCoder encodeObject:_action forKey:CPControlActionKey];
|
||||
|
||||
[aCoder encodeInt:_sendActionOn forKey:CPControlSendActionOnKey];
|
||||
|
||||
@@ -571,29 +571,28 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
|
||||
return YES;
|
||||
|
||||
// Cocoa does not consider space, backspace, or escape a key equivalent
|
||||
// if the first responder is a text field (presumably a subclass of NSText).
|
||||
var firstResponderIsText = [[_window firstResponder] isKindOfClass:[CPTextField class]];
|
||||
|
||||
for (var i = 0; i < characterCount; i++)
|
||||
{
|
||||
switch (_characters.charAt(i))
|
||||
var c = _characters.charAt(i);
|
||||
|
||||
if ((c >= CPUpArrowFunctionKey && c <= CPModeSwitchFunctionKey) ||
|
||||
c === CPEnterCharacter ||
|
||||
c === CPNewlineCharacter ||
|
||||
c === CPCarriageReturnCharacter ||
|
||||
c === CPEscapeFunctionKey ||
|
||||
(!firstResponderIsText &&
|
||||
(c === CPSpaceFunctionKey ||
|
||||
c === CPDeleteCharacter ||
|
||||
c === CPBackspaceCharacter)))
|
||||
{
|
||||
case CPBackspaceCharacter:
|
||||
case CPDeleteCharacter:
|
||||
case CPDeleteFunctionKey:
|
||||
case CPTabCharacter:
|
||||
case CPCarriageReturnCharacter:
|
||||
case CPNewlineCharacter:
|
||||
case CPSpaceFunctionKey:
|
||||
case CPEscapeFunctionKey:
|
||||
case CPPageUpFunctionKey:
|
||||
case CPPageDownFunctionKey:
|
||||
case CPLeftArrowFunctionKey:
|
||||
case CPUpArrowFunctionKey:
|
||||
case CPRightArrowFunctionKey:
|
||||
case CPDownArrowFunctionKey:
|
||||
case CPEndFunctionKey:
|
||||
case CPHomeFunctionKey:
|
||||
return YES;
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: More cases?
|
||||
return NO;
|
||||
}
|
||||
@@ -651,4 +650,3 @@ function _CPEventFromNativeMouseEvent(aNativeEvent, anEventType, aPoint, modifie
|
||||
|
||||
return aNativeEvent;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,8 @@ CPImageNameColorPanel = @"CPImageNameColorPanel";
|
||||
CPImageNameColorPanelHighlighted = @"CPImageNameColorPanelHighlighted";
|
||||
|
||||
var imagesForNames = { },
|
||||
AppKitImageForNames = { };
|
||||
AppKitImageForNames = { },
|
||||
ImageDescriptionFormat = "%s {\n filename: \"%s\",\n size: { width:%f, height:%f }\n}";
|
||||
|
||||
AppKitImageForNames[CPImageNameColorPanel] = CGSizeMake(26.0, 29.0);
|
||||
AppKitImageForNames[CPImageNameColorPanelHighlighted] = CGSizeMake(26.0, 29.0);
|
||||
@@ -324,6 +325,24 @@ function CPAppKitImage(aFilename, aSize)
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
var filename = [self filename],
|
||||
size = [self size];
|
||||
|
||||
if (filename.indexOf("data:") === 0)
|
||||
{
|
||||
var index = filename.indexOf(",");
|
||||
|
||||
if (index > 0)
|
||||
filename = [CPString stringWithFormat:@"%s,%s...%s", filename.substr(0, index), filename.substr(index + 1, 10), filename.substr(filename.length - 10)];
|
||||
else
|
||||
filename = "data:<unknown type>";
|
||||
}
|
||||
|
||||
return [CPString stringWithFormat:ImageDescriptionFormat, [super description], filename, size.width, size.height];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_derefFromImage
|
||||
{
|
||||
|
||||
@@ -204,7 +204,6 @@ var CPBindingOperationAnd = 0,
|
||||
if (valueTransformer)
|
||||
aValue = [valueTransformer transformedValue:aValue];
|
||||
|
||||
|
||||
if (aValue === undefined || aValue === nil || aValue === [CPNull null])
|
||||
aValue = [options objectForKey:CPNullPlaceholderBindingOption] || nil;
|
||||
|
||||
@@ -311,7 +310,7 @@ var CPBindingOperationAnd = 0,
|
||||
- (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);
|
||||
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);
|
||||
@@ -488,6 +487,8 @@ CPSelectedIndexBinding = @"selectedIndex";
|
||||
CPTextColorBinding = @"textColor";
|
||||
CPToolTipBinding = @"toolTip";
|
||||
CPValueBinding = @"value";
|
||||
CPContentBinding = @"content";
|
||||
CPContentValuesBinding = @"contentValues";
|
||||
|
||||
//Binding options constants
|
||||
CPAllowsEditingMultipleValuesSelectionBindingOption = @"CPAllowsEditingMultipleValuesSelection";
|
||||
@@ -518,4 +519,4 @@ CPValueTransformerBindingOption = @"CPValueTransformer";
|
||||
CPIsControllerMarker = function(/*id*/anObject)
|
||||
{
|
||||
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker || anObject === CPNullMarker;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,9 +149,9 @@ var _CPLevelIndicatorBezelColor = nil,
|
||||
var filledColor = _CPLevelIndicatorSegmentNormalColor,
|
||||
value = [self doubleValue];
|
||||
|
||||
if (value < _criticalValue)
|
||||
if (value <= _criticalValue)
|
||||
filledColor = _CPLevelIndicatorSegmentCriticalColor;
|
||||
else if (value < _warningValue)
|
||||
else if (value <= _warningValue)
|
||||
filledColor = _CPLevelIndicatorSegmentWarningColor;
|
||||
|
||||
for (var i = 0; i < segmentCount; i++)
|
||||
|
||||
@@ -622,11 +622,11 @@ var _CPMenuBarVisible = NO,
|
||||
var validator = [CPApp targetForAction:[item action] to:[item target] from:item];
|
||||
|
||||
if (!validator || ![validator respondsToSelector:[item action]])
|
||||
[item _setEnabled:NO];
|
||||
[item setEnabled:NO];
|
||||
else if ([validator respondsToSelector:@selector(validateMenuItem:)])
|
||||
[item _setEnabled:[validator validateMenuItem:item]];
|
||||
[item setEnabled:[validator validateMenuItem:item]];
|
||||
else if ([validator respondsToSelector:@selector(validateUserInterfaceItem:)])
|
||||
[item _setEnabled:[validator validateUserInterfaceItem:item]];
|
||||
[item setEnabled:[validator validateUserInterfaceItem:item]];
|
||||
}
|
||||
|
||||
[[_menuWindow _menuView] tile];
|
||||
@@ -711,10 +711,7 @@ var _CPMenuBarVisible = NO,
|
||||
if (aView && !theWindow)
|
||||
throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, view is not in any window.";
|
||||
|
||||
var delegate = [self delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||
[delegate menuWillOpen:self];
|
||||
[self _menuWillOpen];
|
||||
|
||||
// Convert location to global coordinates if not already in them.
|
||||
if (aView)
|
||||
@@ -802,10 +799,7 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
+ (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont
|
||||
{
|
||||
var delegate = [aMenu delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||
[delegate menuWillOpen:aMenu];
|
||||
[aMenu _menuWillOpen];
|
||||
|
||||
if (!aFont)
|
||||
aFont = [CPFont systemFontOfSize:12.0];
|
||||
@@ -875,7 +869,15 @@ var _CPMenuBarVisible = NO,
|
||||
*/
|
||||
- (CPMenuItem)highlightedItem
|
||||
{
|
||||
return _highlightedIndex >= 0 ? _items[_highlightedIndex] : nil;
|
||||
if (_highlightedIndex < 0)
|
||||
return nil;
|
||||
|
||||
var highlightedItem = _items[_highlightedIndex];
|
||||
|
||||
if ([highlightedItem isSeparatorItem])
|
||||
return nil;
|
||||
|
||||
return highlightedItem;
|
||||
}
|
||||
|
||||
// Managing the Delegate
|
||||
@@ -890,6 +892,22 @@ var _CPMenuBarVisible = NO,
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
- (void)_menuWillOpen
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||
[delegate menuWillOpen:self];
|
||||
}
|
||||
|
||||
- (void)_menuDidClose
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuDidClose:)])
|
||||
[delegate menuDidClose:self];
|
||||
}
|
||||
|
||||
// Handling Tracking
|
||||
/*!
|
||||
Cancels tracking.
|
||||
|
||||
@@ -11,6 +11,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
@implementation _CPMenuManager: CPObject
|
||||
{
|
||||
CPTimeInterval _startTime;
|
||||
BOOL _hasMouseGoneUpAfterStartedTracking;
|
||||
int _scrollingState;
|
||||
CGPoint _lastGlobalLocation;
|
||||
|
||||
@@ -60,6 +61,9 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
{
|
||||
var menu = [aMenuContainer menu];
|
||||
|
||||
if ([menu numberOfItems] <= 0)
|
||||
return;
|
||||
|
||||
CPApp._activeMenu = menu;
|
||||
|
||||
_startTime = [anEvent timestamp];//new Date();
|
||||
@@ -87,6 +91,8 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
return [self trackMenuBarButtonEvent:anEvent];
|
||||
}
|
||||
|
||||
_hasMouseGoneUpAfterStartedTracking = NO;
|
||||
|
||||
[self trackEvent:anEvent];
|
||||
}
|
||||
|
||||
@@ -99,7 +105,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
if (type === CPAppKitDefined)
|
||||
return [self completeTracking];
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPKeyDownMask | CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask | CPScrollWheelMask untilDate:nil inMode:nil dequeue:YES];
|
||||
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPKeyDownMask | CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPRightMouseUpMask | CPAppKitDefinedMask | CPScrollWheelMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
if (type === CPKeyDown)
|
||||
{
|
||||
@@ -221,8 +227,20 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
[CPEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.04];
|
||||
}
|
||||
}
|
||||
else if (type === CPLeftMouseUp && ([anEvent timestamp] - _startTime > (STICKY_TIME_INTERVAL + [activeMenu numberOfItems] * 5)))
|
||||
[trackingMenu cancelTracking];
|
||||
else if (type === CPLeftMouseUp || type === CPRightMouseUp)
|
||||
{
|
||||
if (_hasMouseGoneUpAfterStartedTracking)
|
||||
{
|
||||
// Don't close the menu if the current item has a submenu
|
||||
// and did not override it's default action
|
||||
if ([activeItem action] === @selector(submenuAction:))
|
||||
return;
|
||||
|
||||
[trackingMenu cancelTracking];
|
||||
}
|
||||
else
|
||||
_hasMouseGoneUpAfterStartedTracking = YES;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent previous selected menu items from opening by stopping the timer if a
|
||||
@@ -306,11 +324,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
// Hide all submenus.
|
||||
[self showMenu:nil fromMenu:trackingMenu atPoint:nil];
|
||||
|
||||
var delegate = [trackingMenu delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuDidClose:)])
|
||||
[delegate menuDidClose:trackingMenu];
|
||||
[trackingMenu _menuDidClose];
|
||||
|
||||
if (_trackingCallback)
|
||||
_trackingCallback([self trackingMenuContainer], trackingMenu);
|
||||
@@ -379,6 +393,8 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
var count = _menuContainerStack.length,
|
||||
index = count;
|
||||
|
||||
[newMenu _menuWillOpen];
|
||||
|
||||
// Hide all menus up to the base menu...
|
||||
while (index--)
|
||||
{
|
||||
@@ -398,6 +414,8 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
[_CPMenuWindow poolMenuWindow:menuContainer];
|
||||
[_menuContainerStack removeObjectAtIndex:index];
|
||||
|
||||
[menu _menuDidClose];
|
||||
}
|
||||
|
||||
if (!newMenu)
|
||||
|
||||
@@ -148,14 +148,6 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
|
||||
@param isEnabled \c YES enables the item. \c NO disables it.
|
||||
*/
|
||||
- (void)setEnabled:(BOOL)isEnabled
|
||||
{
|
||||
if ([_menu autoenablesItems])
|
||||
return;
|
||||
|
||||
[self _setEnabled:isEnabled];
|
||||
}
|
||||
|
||||
- (void)_setEnabled:(BOOL)isEnabled
|
||||
{
|
||||
if (_isEnabled === isEnabled)
|
||||
return;
|
||||
@@ -496,6 +488,7 @@ CPOffState
|
||||
if (_submenu)
|
||||
{
|
||||
[_submenu setSupermenu:_menu];
|
||||
[_submenu setTitle:[self title]]
|
||||
|
||||
[self setTarget:_menu];
|
||||
[self setAction:@selector(submenuAction:)];
|
||||
|
||||
@@ -131,8 +131,8 @@
|
||||
|
||||
_contentObject = aContent;
|
||||
|
||||
[self didChangeValueForKey:@"contentObject"];
|
||||
[self _selectionDidChange];
|
||||
[self didChangeValueForKey:@"contentObject"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -323,12 +323,22 @@
|
||||
@ignore
|
||||
*/
|
||||
- (void)_selectionDidChange
|
||||
{
|
||||
[self _selectionDidChangeNotify:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)_selectionDidChangeNotify:(BOOL)notify
|
||||
{
|
||||
if (_selection === undefined || _selection === nil)
|
||||
_selection = [[CPControllerSelectionProxy alloc] initWithController:self];
|
||||
|
||||
[_selection controllerDidChange];
|
||||
[self didChangeValueForKey:@"selection"];
|
||||
|
||||
if (notify)
|
||||
[self didChangeValueForKey:@"selection"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -666,21 +676,21 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
var count = [theValues count];
|
||||
|
||||
if (!count)
|
||||
value = CPNoSelectionMarker;
|
||||
return CPNoSelectionMarker;
|
||||
else if (count === 1)
|
||||
value = [theValues objectAtIndex:0];
|
||||
else
|
||||
{
|
||||
if ([_controller alwaysUsesMultipleValuesMarker])
|
||||
value = CPMultipleValuesMarker;
|
||||
return CPMultipleValuesMarker;
|
||||
else
|
||||
{
|
||||
value = [theValues objectAtIndex:0];
|
||||
|
||||
for (var i = 0, count= [theValues count]; i < count && value != CPMultipleValuesMarker; i++)
|
||||
for (var i = 0, count = [theValues count]; i < count; i++)
|
||||
{
|
||||
if (![value isEqual:[theValues objectAtIndex:i]])
|
||||
value = CPMultipleValuesMarker;
|
||||
return CPMultipleValuesMarker;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -693,8 +703,21 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
- (id)valueForKeyPath:(CPString)theKeyPath
|
||||
{
|
||||
var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath];
|
||||
value = [self _controllerMarkerForValues:values];
|
||||
// If valueForKeyPath fails because of an undefined key, return CPNotApplicableMarker
|
||||
var value;
|
||||
|
||||
try
|
||||
{
|
||||
var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath];
|
||||
value = [self _controllerMarkerForValues:values];
|
||||
}
|
||||
catch (ex)
|
||||
{
|
||||
if ([ex name] === CPUndefinedKeyException)
|
||||
value = CPNotApplicableMarker;
|
||||
else
|
||||
throw ex;
|
||||
}
|
||||
|
||||
[_cachedValues setObject:value forKey:theKeyPath];
|
||||
|
||||
|
||||
@@ -1458,6 +1458,44 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||
}
|
||||
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
{
|
||||
var character = [anEvent charactersIgnoringModifiers],
|
||||
modifierFlags = [anEvent modifierFlags];
|
||||
|
||||
// Check for the key events manually, as opposed to waiting for CPWindow to sent the actual action message
|
||||
// in _processKeyboardUIKey:, because we might not want to handle the arrow events.
|
||||
|
||||
if (character !== CPRightArrowFunctionKey && character !== CPLeftArrowFunctionKey)
|
||||
return [super keyDown:anEvent];
|
||||
|
||||
var rows = [self selectedRowIndexes],
|
||||
indexes = [],
|
||||
items = [];
|
||||
|
||||
[rows getIndexes:indexes maxCount:-1 inIndexRange:nil];
|
||||
|
||||
var i = 0,
|
||||
c = [indexes count];
|
||||
|
||||
for (; i < c; i++)
|
||||
items.push([self itemAtRow:indexes[i]]);
|
||||
|
||||
|
||||
if (character === CPRightArrowFunctionKey)
|
||||
{
|
||||
for (var i = 0; i < c; i++)
|
||||
[self expandItem:items[i]];
|
||||
}
|
||||
else if (character === CPLeftArrowFunctionKey)
|
||||
{
|
||||
for (var i = 0; i < c; i++)
|
||||
[self collapseItem:items[i]];
|
||||
}
|
||||
|
||||
[super keyDown:anEvent];
|
||||
}
|
||||
@end
|
||||
|
||||
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
|
||||
|
||||
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* CPPopover.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Antoine Mercadal.
|
||||
* Copyright 2011 Antoine Mercadal.
|
||||
*
|
||||
* 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 "CPButton.j"
|
||||
@import "CPColor.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPImageView.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPView.j"
|
||||
@import "_CPAttachedWindow.j"
|
||||
|
||||
|
||||
CPPopoverBehaviorApplicationDefined = 0;
|
||||
CPPopoverBehaviorTransient = 1;
|
||||
CPPopoverBehaviorSemitransient = 2;
|
||||
|
||||
|
||||
var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
||||
CPPopoverDelegate_popover_didShow_ = 1 << 1,
|
||||
CPPopoverDelegate_popover_shouldClose_ = 1 << 2,
|
||||
CPPopoverDelegate_popover_willClose_ = 1 << 3,
|
||||
CPPopoverDelegate_popover_didClose_ = 1 << 4;
|
||||
|
||||
|
||||
/*! @ingroup appkit
|
||||
@class CPPopover
|
||||
|
||||
This class represent a widget that displays a attached
|
||||
view relative to another one.
|
||||
|
||||
Delegate can implement:
|
||||
– popoverShouldClose:(CPPopover)aPopOver
|
||||
– popoverWillShow:(CPPopover)aPopOver
|
||||
– popoverDidShow:(CPPopover)aPopOver
|
||||
– popoverWillClose:(CPPopover)aPopOver
|
||||
– popoverDidClose:(CPPopover)aPopOver
|
||||
*/
|
||||
@implementation CPPopover : CPResponder
|
||||
{
|
||||
@outlet CPViewController _contentViewController @accessors(property=contentViewController);
|
||||
@outlet id _delegate @accessors(getter=delegate);
|
||||
|
||||
BOOL _animates @accessors(property=animates);
|
||||
BOOL _shown @accessors(getter=shown);
|
||||
int _appearance @accessors(property=appearance);
|
||||
int _behavior @accessors(getter=behavior);
|
||||
|
||||
BOOL _needsCompute;
|
||||
_CPAttachedWindow _attachedWindow;
|
||||
int _implementedDelegateMethods;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark INitialization
|
||||
|
||||
/*!
|
||||
Initialize the CPPopover witn default values
|
||||
|
||||
@returns anInitialized CPPopover
|
||||
*/
|
||||
- (CPPopover)init
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_animates = YES;
|
||||
_appearance = CPPopoverAppearanceMinimal;
|
||||
_behavior = CPPopoverBehaviorApplicationDefined;
|
||||
_needsCompute = YES;
|
||||
_shown = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Getters / Setters
|
||||
|
||||
/*!
|
||||
Returns the current rect of the popover
|
||||
|
||||
@return CPRect represeting the frame of the popover
|
||||
*/
|
||||
- (CPRect)positionningRect
|
||||
{
|
||||
if (!_attachedWindow || ![_attachedWindow isVisible])
|
||||
return nil;
|
||||
return [_attachedWindow frame];
|
||||
}
|
||||
|
||||
/*! Sets the frame of the popover
|
||||
@param aRect the desired frame
|
||||
*/
|
||||
- (void)setPositionningRect:(CPRect)aRect
|
||||
{
|
||||
if (!_attachedWindow || ![_attachedWindow isVisible])
|
||||
return;
|
||||
[_attachedWindow setFrame:aRect];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the size of the popover's view
|
||||
|
||||
@return CPSize represeting the size of the popover's view
|
||||
*/
|
||||
- (CPRect)contentSize
|
||||
{
|
||||
if (!_attachedWindow || ![_attachedWindow isVisible])
|
||||
return nil;
|
||||
return [[_contentViewController view] frameSize];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the size of of the popover's view
|
||||
|
||||
@param aSize the desired size
|
||||
*/
|
||||
- (void)setContentSize:(CPSize)aSize
|
||||
{
|
||||
[[_contentViewController view] setFrameSize:aSize];
|
||||
}
|
||||
|
||||
/*!
|
||||
Indicates if CPPopover is visible
|
||||
|
||||
@returns YES if visible
|
||||
*/
|
||||
- (BOOL)shown
|
||||
{
|
||||
if (!_attachedWindow)
|
||||
return NO;
|
||||
return [_attachedWindow isVisible];
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the behaviour of the CPPopover. It can be
|
||||
- CPPopoverBehaviorTransient: the popover will be close if another control outside the popover become the responder
|
||||
- CPPopoverBehaviorApplicationDefined: (DEFAULT) the application is responsible for closing the popover
|
||||
|
||||
@param aBehaviour the desired behaviour
|
||||
*/
|
||||
- (void)setBehaviour:(int)aBehaviour
|
||||
{
|
||||
if (_behavior == aBehaviour)
|
||||
return;
|
||||
|
||||
_behavior = aBehaviour;
|
||||
_needsCompute = YES;
|
||||
}
|
||||
|
||||
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
if (_delegate === aDelegate)
|
||||
return;
|
||||
|
||||
_delegate = aDelegate;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverWillShow:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_willShow_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverDidShow:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_didShow_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverShouldClose:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_shouldClose_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverWillClose:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_willClose_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverDidClose:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_didClose_;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Positionning
|
||||
|
||||
/*!
|
||||
Show the popover
|
||||
|
||||
@param positioningRect if set, the popover will be positionned to a random rect relative to the window
|
||||
@param positioningView if set, the popover will be positioned relative to this view
|
||||
@param preferredEdge: CPRectEdge representing the prefered positionning.
|
||||
*/
|
||||
- (void)showRelativeToRect:(CPRect)positioningRect ofView:(CPView)positioningView preferredEdge:(CPRectEdge)preferredEdge
|
||||
{
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willShow_)
|
||||
[_delegate popoverWillShow:self];
|
||||
|
||||
if (!_contentViewController)
|
||||
[CPException raise:CPInternalInconsistencyException reason:@"contentViewController must not be nil"];
|
||||
|
||||
if (_needsCompute)
|
||||
{
|
||||
var styleMask = (_behavior == CPPopoverBehaviorTransient) ? CPClosableOnBlurWindowMask : nil;
|
||||
_attachedWindow = [[_CPAttachedWindow alloc] initWithContentRect:CPRectMakeZero() styleMask:styleMask];
|
||||
}
|
||||
|
||||
[_attachedWindow setAppearance:_appearance];
|
||||
[_attachedWindow setAnimates:_animates];
|
||||
[_attachedWindow setMovableByWindowBackground:NO];
|
||||
[_attachedWindow setFrame:[_attachedWindow frameRectForContentRect:[[_contentViewController view] frame]]];
|
||||
[_attachedWindow setContentView:[_contentViewController view]];
|
||||
|
||||
if (positioningRect)
|
||||
[_attachedWindow positionRelativeToRect:positioningRect preferredEdge:preferredEdge];
|
||||
else if (positioningView)
|
||||
[_attachedWindow positionRelativeToView:positioningView preferredEdge:preferredEdge];
|
||||
else
|
||||
[CPException raise:CPInvalidArgumentException reason:@"you must set positioningRect or positioningRect"];
|
||||
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didShow_)
|
||||
[_delegate popoverDidShow:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
Closes the popover
|
||||
*/
|
||||
- (void)close
|
||||
{
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_shouldClose_)
|
||||
if (![_delegate popoverShouldClose:self])
|
||||
return;
|
||||
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willClose_)
|
||||
[_delegate popoverWillClose:self];
|
||||
|
||||
[_attachedWindow close];
|
||||
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didClose_)
|
||||
[_delegate popoverDidClose:self];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Action
|
||||
|
||||
/*!
|
||||
Close the popover
|
||||
|
||||
@param aSender the sender of the action
|
||||
*/
|
||||
- (IBAction)performClose:(id)aSender
|
||||
{
|
||||
[self close];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPPopover (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_needsCompute = [aCoder decodeIntForKey:@"_needsCompute"];
|
||||
_appearance = [aCoder decodeIntForKey:@"_appearance"];
|
||||
_animates = [aCoder decodeBoolForKey:@"_animates"];
|
||||
_contentViewController = [aCoder decodeObjectForKey:@"_contentViewController"];
|
||||
[self setDelegate:[aCoder decodeObjectForKey:@"_delegate"]];
|
||||
[self setBehaviour:[aCoder decodeIntForKey:@"_behavior"]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeInt:_behavior forKey:@"_behavior"];
|
||||
[aCoder encodeInt:_appearance forKey:@"_appearance"];
|
||||
[aCoder encodeBool:_needsCompute forKey:@"_needsCompute"];
|
||||
[aCoder encodeObject:_contentViewController forKey:@"_contentViewController"];
|
||||
[aCoder encodeObject:_delegate forKey:@"_delegate"];
|
||||
[aCoder encodeObject:_animates forKey:@"_animates"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -34,6 +34,12 @@
|
||||
places scroll bars on the side of the view to allow the user to scroll and see the entire
|
||||
contents of the view.
|
||||
*/
|
||||
|
||||
var TIMER_INTERVAL = 0.2,
|
||||
CPScrollViewDelegate_scrollViewWillScroll_ = 1 << 0,
|
||||
CPScrollViewDelegate_scrollViewDidScroll_ = 1 << 1;
|
||||
|
||||
|
||||
@implementation CPScrollView : CPView
|
||||
{
|
||||
CPClipView _contentView;
|
||||
@@ -41,6 +47,9 @@
|
||||
CPView _cornerView;
|
||||
CPView _bottomCornerView;
|
||||
|
||||
id _delegate;
|
||||
CPTimer _scrollTimer;
|
||||
|
||||
BOOL _hasVerticalScroller;
|
||||
BOOL _hasHorizontalScroller;
|
||||
BOOL _autohidesScrollers;
|
||||
@@ -48,7 +57,8 @@
|
||||
CPScroller _verticalScroller;
|
||||
CPScroller _horizontalScroller;
|
||||
|
||||
int _recursionCount;
|
||||
CPInteger _recursionCount;
|
||||
CPInteger _implementedDelegateMethods;
|
||||
|
||||
float _verticalLineScroll;
|
||||
float _verticalPageScroll;
|
||||
@@ -86,7 +96,6 @@
|
||||
_borderType = CPNoBorder;
|
||||
|
||||
_contentView = [[CPClipView alloc] initWithFrame:[self _insetBounds]];
|
||||
|
||||
[self addSubview:_contentView];
|
||||
|
||||
_headerClipView = [[CPClipView alloc] init];
|
||||
@@ -97,11 +106,37 @@
|
||||
|
||||
[self setHasVerticalScroller:YES];
|
||||
[self setHasHorizontalScroller:YES];
|
||||
|
||||
_delegate = nil;
|
||||
_scrollTimer = nil;
|
||||
_implementedDelegateMethods = 0;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)delegate
|
||||
{
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
if (aDelegate === _delegate)
|
||||
return;
|
||||
|
||||
_delegate = aDelegate;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
if (_delegate === nil)
|
||||
return;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(scrollViewWillScroll:)])
|
||||
_implementedDelegateMethods |= CPScrollViewDelegate_scrollViewWillScroll_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(scrollViewDidScroll:)])
|
||||
_implementedDelegateMethods |= CPScrollViewDelegate_scrollViewDidScroll_;
|
||||
}
|
||||
// Calculating Layout
|
||||
|
||||
+ (CGSize)contentSizeForFrameSize:(CGSize)frameSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
|
||||
@@ -655,6 +690,8 @@
|
||||
default: contentBounds.origin.y = ROUND(value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds)));
|
||||
}
|
||||
|
||||
[self _sendDelegateMessages];
|
||||
|
||||
[_contentView scrollToPoint:contentBounds.origin];
|
||||
}
|
||||
|
||||
@@ -685,6 +722,8 @@
|
||||
default: contentBounds.origin.x = ROUND(value * (_CGRectGetWidth(documentFrame) - _CGRectGetWidth(contentBounds)));
|
||||
}
|
||||
|
||||
[self _sendDelegateMessages];
|
||||
|
||||
[_contentView scrollToPoint:contentBounds.origin];
|
||||
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)];
|
||||
}
|
||||
@@ -962,6 +1001,8 @@
|
||||
extraX = contentBounds.origin.x - constrainedOrigin.x,
|
||||
extraY = contentBounds.origin.y - constrainedOrigin.y;
|
||||
|
||||
[self _sendDelegateMessages];
|
||||
|
||||
[_contentView scrollToPoint:constrainedOrigin];
|
||||
[_headerClipView scrollToPoint:CGPointMake(constrainedOrigin.x, 0.0)];
|
||||
|
||||
@@ -1029,6 +1070,35 @@
|
||||
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0)];
|
||||
}
|
||||
|
||||
- (void)_sendDelegateMessages
|
||||
{
|
||||
if (_implementedDelegateMethods == 0)
|
||||
return;
|
||||
|
||||
if (!_scrollTimer)
|
||||
{
|
||||
[self _scrollViewWillScroll];
|
||||
_scrollTimer = [CPTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self selector:@selector(_scrollViewDidScroll) userInfo:nil repeats:YES];
|
||||
}
|
||||
else
|
||||
[_scrollTimer setFireDate:[CPDate dateWithTimeIntervalSinceNow:TIMER_INTERVAL]];
|
||||
}
|
||||
|
||||
- (void)_scrollViewWillScroll
|
||||
{
|
||||
if (_implementedDelegateMethods & CPScrollViewDelegate_scrollViewWillScroll_)
|
||||
[_delegate scrollViewWillScroll:self];
|
||||
}
|
||||
|
||||
- (void)_scrollViewDidScroll
|
||||
{
|
||||
[_scrollTimer invalidate];
|
||||
_scrollTimer = nil;
|
||||
|
||||
if (_implementedDelegateMethods & CPScrollViewDelegate_scrollViewDidScroll_)
|
||||
[_delegate scrollViewDidScroll:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPScrollViewContentViewKey = @"CPScrollViewContentView",
|
||||
@@ -1079,6 +1149,9 @@ var CPScrollViewContentViewKey = @"CPScrollViewContentView",
|
||||
_cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
|
||||
_bottomCornerView = [aCoder decodeObjectForKey:CPScrollViewBottomCornerViewKey];
|
||||
|
||||
_delegate = nil;
|
||||
_scrollTimer = nil;
|
||||
_implementedDelegateMethods = 0;
|
||||
// Due to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state.
|
||||
[[CPRunLoop currentRunLoop] performSelector:@selector(_updateCornerAndHeaderView) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
|
||||
}
|
||||
|
||||
@@ -457,8 +457,9 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
}
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackKnob:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
if (type === CPLeftMouseDragged)
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -45,6 +45,7 @@ CPSoundPlayBackStatePause = 2;
|
||||
CPString _name @accessors(property=name);
|
||||
id _delegate @accessors(property=delegate);
|
||||
|
||||
BOOL _playRequestBeforeLoad;
|
||||
HTMLAudioElement _audioTag;
|
||||
int _loadStatus;
|
||||
int _playBackStatus;
|
||||
@@ -61,6 +62,7 @@ CPSoundPlayBackStatePause = 2;
|
||||
_loops = NO;
|
||||
_audioTag = document.createElement("audio");
|
||||
_audioTag.preload = YES;
|
||||
_playRequestBeforeLoad = NO;
|
||||
|
||||
_audioTag.addEventListener("canplay", function()
|
||||
{
|
||||
@@ -138,6 +140,12 @@ CPSoundPlayBackStatePause = 2;
|
||||
- (void)_soundDidload
|
||||
{
|
||||
_loadStatus = CPSoundLoadStateCanBePlayed;
|
||||
|
||||
if (_playRequestBeforeLoad)
|
||||
{
|
||||
_playRequestBeforeLoad = NO;
|
||||
[self play];
|
||||
}
|
||||
}
|
||||
|
||||
/*! @ignore
|
||||
@@ -167,6 +175,12 @@ CPSoundPlayBackStatePause = 2;
|
||||
*/
|
||||
- (BOOL)play
|
||||
{
|
||||
if (_loadStatus === CPSoundLoadStateLoading)
|
||||
{
|
||||
_playRequestBeforeLoad = YES;
|
||||
return YES;
|
||||
}
|
||||
|
||||
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|
||||
|| (_playBackStatus === CPSoundPlayBackStatePlay))
|
||||
return NO;
|
||||
|
||||
@@ -332,18 +332,18 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
|
||||
|
||||
Example:
|
||||
@code
|
||||
[tableColumn setDataView:someView]; // snapshot taken
|
||||
[[tableColumn dataView] setSomething:x]; //won't work
|
||||
@endcode
|
||||
@code
|
||||
[tableColumn setDataView:someView]; // snapshot taken
|
||||
[[tableColumn dataView] setSomething:x]; //won't work
|
||||
@endcode
|
||||
|
||||
This doesn't work because the snapshot is taken before the new property is applied. Instead, do:
|
||||
@code
|
||||
[someView setSomething:x];
|
||||
[tableColumn setDataView:someView];
|
||||
@endcode
|
||||
@code
|
||||
[someView setSomething:x];
|
||||
[tableColumn setDataView:someView];
|
||||
@endcode
|
||||
|
||||
@note you should implement CPKeyedArchiving otherwise you might see unexpected results.
|
||||
@note You should implement CPKeyedArchiving otherwise you might see unexpected results.
|
||||
This is done by adding the following methods to your class:
|
||||
@endnote
|
||||
|
||||
@@ -380,7 +380,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@section Themeing
|
||||
@section Theming
|
||||
|
||||
When you set a dataview and it is added to the tableview the theme state will be set to \c CPThemeStateTableDataView
|
||||
When the dataview becomes selected the theme state will be set to \c CPThemeStateSelectedDataView.
|
||||
|
||||
@@ -323,6 +323,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
{
|
||||
_tableViewFlags = 0;
|
||||
_lastSelectedRow = -1;
|
||||
_clickedRow = -1;
|
||||
|
||||
_selectedColumnIndexes = [CPIndexSet indexSet];
|
||||
_selectedRowIndexes = [CPIndexSet indexSet];
|
||||
@@ -2770,7 +2771,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
*/
|
||||
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes atPoint:(CGPoint)mouseDownPoint
|
||||
{
|
||||
return YES;
|
||||
return [rowIndexes count] > 0 && [self numberOfRows] > 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -3544,16 +3545,16 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
}
|
||||
|
||||
var exposedRows = [self _unboundedRowsInRect:aRect],
|
||||
firstRow = FLOOR(exposedRows.location / colorCount) * colorCount,
|
||||
lastRow = CPMaxRange(exposedRows),
|
||||
colorIndex = 0,
|
||||
groupRowRects = [],
|
||||
row = exposedRows.location;
|
||||
groupRowRects = [];
|
||||
|
||||
//loop through each color so we only draw once for each color
|
||||
while (colorIndex < colorCount)
|
||||
{
|
||||
CGContextBeginPath(context);
|
||||
for (var row = colorIndex; row <= lastRow; row += colorCount)
|
||||
for (var row = firstRow + colorIndex; row <= lastRow; row += colorCount)
|
||||
{
|
||||
// if it's not a group row draw it otherwise we draw it later
|
||||
if (![_groupRows containsIndex:row])
|
||||
@@ -4609,7 +4610,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
}
|
||||
_wasSelectionBroken = true;
|
||||
}
|
||||
else if (_wasSelectionBroken && ((shouldGoUpward && i !== [selectedIndexes firstIndex]) || (!shouldGoUpward && i !== [selectedIndexes lastindex])))
|
||||
else if (_wasSelectionBroken && ((shouldGoUpward && i !== [selectedIndexes firstIndex]) || (!shouldGoUpward && i !== [selectedIndexes lastIndex])))
|
||||
{
|
||||
shouldGoUpward ? i = [selectedIndexes firstIndex] - 1 : i = [selectedIndexes lastIndex];
|
||||
_wasSelectionBroken = false;
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#import "../Foundation/Ref.h"
|
||||
|
||||
@import "CPControl.j"
|
||||
@import "CPStringDrawing.j"
|
||||
@import "CPCompatibility.j"
|
||||
@@ -83,12 +85,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
CPColor _textFieldBackgroundColor;
|
||||
|
||||
id _placeholderString;
|
||||
CPString _placeholderString;
|
||||
CPString _stringValue;
|
||||
|
||||
id _delegate;
|
||||
|
||||
CPString _textDidChangeValue;
|
||||
|
||||
// NS-style Display Properties
|
||||
CPTextFieldBezelStyle _bezelStyle;
|
||||
BOOL _isBordered;
|
||||
@@ -168,8 +169,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(2.0, 2.0, 2.0, 2.0), [CPNull null]]
|
||||
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
|
||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(2.0, 2.0, 2.0, 2.0), _CGInsetMake(3.0, 3.0, 3.0, 3.0), [CPNull null]]
|
||||
forKeys:[@"bezel-inset", @"content-inset", @"border-inset", @"bezel-color"]];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
@@ -481,17 +482,17 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[self setNeedsLayout];
|
||||
|
||||
_isEditing = NO;
|
||||
_stringValue = [self stringValue];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var string = [self stringValue],
|
||||
element = [self _inputElement],
|
||||
var element = [self _inputElement],
|
||||
font = [self currentValueForThemeAttribute:@"font"];
|
||||
|
||||
// generate the font metric
|
||||
[font _getMetrics];
|
||||
|
||||
element.value = string;
|
||||
element.value = _stringValue;
|
||||
element.style.color = [[self currentValueForThemeAttribute:@"text-color"] cssString];
|
||||
element.style.font = [font cssString];
|
||||
element.style.zIndex = 1000;
|
||||
@@ -506,31 +507,32 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
}
|
||||
|
||||
var contentRect = [self contentRectForBounds:[self bounds]],
|
||||
verticalAlign = [self currentValueForThemeAttribute:"vertical-alignment"];
|
||||
verticalAlign = [self currentValueForThemeAttribute:"vertical-alignment"],
|
||||
lineHeight = [font defaultLineHeightForFont];
|
||||
|
||||
switch (verticalAlign)
|
||||
{
|
||||
case CPTopVerticalTextAlignment:
|
||||
var topPoint = (_CGRectGetMinY(contentRect) + 1) + "px"; // for the same reason we have a -1 for the left, we also have a + 1 here
|
||||
var topPoint = _CGRectGetMinY(contentRect) + "px"; // for the same reason we have a -1 for the left, we also have a + 1 here
|
||||
break;
|
||||
|
||||
case CPCenterVerticalTextAlignment:
|
||||
var topPoint = (_CGRectGetMidY(contentRect) - (font._lineHeight / 2) + 1) + "px";
|
||||
var topPoint = (_CGRectGetMidY(contentRect) - (lineHeight / 2)) + "px";
|
||||
break;
|
||||
|
||||
case CPBottomVerticalTextAlignment:
|
||||
var topPoint = (_CGRectGetMaxY(contentRect) - font._lineHeight) + "px";
|
||||
var topPoint = (_CGRectGetMaxY(contentRect) - lineHeight) + "px";
|
||||
break;
|
||||
|
||||
default:
|
||||
var topPoint = (_CGRectGetMinY(contentRect) + 1) + "px";
|
||||
var topPoint = _CGRectGetMinY(contentRect) + "px";
|
||||
break;
|
||||
}
|
||||
|
||||
element.style.top = topPoint;
|
||||
element.style.left = (_CGRectGetMinX(contentRect) - 1) + "px"; // why -1?
|
||||
element.style.width = _CGRectGetWidth(contentRect) + "px";
|
||||
element.style.height = font._lineHeight + "px"; // private ivar for the line height of the DOM text at this particular size
|
||||
element.style.height = lineHeight + "px";
|
||||
|
||||
_DOMElement.appendChild(element);
|
||||
|
||||
@@ -548,8 +550,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
CPTextFieldInputOwner = self;
|
||||
}, 0.0);
|
||||
|
||||
element.value = [self stringValue];
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
CPTextFieldInputIsActive = YES;
|
||||
@@ -572,17 +572,33 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
[self unsetThemeState:CPThemeStateEditing];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var element = [self _inputElement],
|
||||
error = @"";
|
||||
|
||||
// If there is a formatter, always give it a chance to reject the resignation,
|
||||
// even if the value has not changed.
|
||||
if ([self _valueIsValid:element.value] === NO)
|
||||
{
|
||||
[self setThemeState:CPThemeStateEditing];
|
||||
element.focus();
|
||||
return NO;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Cache the formatted string
|
||||
_stringValue = [self stringValue];
|
||||
|
||||
_willBecomeFirstResponderByClick = NO;
|
||||
|
||||
[self _updatePlaceholderState];
|
||||
|
||||
[self setNeedsLayout];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var element = [self _inputElement];
|
||||
|
||||
if ([self stringValue] !== element.value)
|
||||
[self _setStringValue:element.value];
|
||||
|
||||
CPTextFieldInputResigning = YES;
|
||||
|
||||
if (CPTextFieldInputIsActive)
|
||||
@@ -610,21 +626,39 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
#endif
|
||||
|
||||
//post CPControlTextDidEndEditingNotification
|
||||
if (_isEditing)
|
||||
{
|
||||
_isEditing = NO;
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
_isEditing = NO;
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
|
||||
if ([self sendsActionOnEndEditing])
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
if ([self sendsActionOnEndEditing])
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
[self textDidBlur:[CPNotification notificationWithName:CPTextFieldDidBlurNotification object:self userInfo:nil]];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)_valueIsValid:(CPString)aValue
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var error = @"";
|
||||
|
||||
if ([self _setStringValue:aValue isNewValue:NO errorDescription:AT_REF(error)] === NO)
|
||||
{
|
||||
var acceptInvalidValue = NO;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(control:didFailToFormatString:errorDescription:)])
|
||||
acceptInvalidValue = [_delegate control:self didFailToFormatString:[self _inputElement] errorDescription:error];
|
||||
|
||||
if (acceptInvalidValue === NO)
|
||||
return NO;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
Text fields require panels to become key window, so this returns \c YES.
|
||||
*/
|
||||
@@ -685,11 +719,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)keyUp:(CPEvent)anEvent
|
||||
{
|
||||
var oldValue = [self stringValue];
|
||||
[self _setStringValue:[self _inputElement].value];
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
if (oldValue !== [self stringValue])
|
||||
var newValue = [self _inputElement].value;
|
||||
|
||||
if (newValue !== _stringValue)
|
||||
{
|
||||
[self _setStringValue:newValue];
|
||||
|
||||
if (!_isEditing)
|
||||
{
|
||||
_isEditing = YES;
|
||||
@@ -699,14 +736,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
}
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
{
|
||||
if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent])
|
||||
return;
|
||||
|
||||
// CPTextField uses an HTML input element to take the input so we need to
|
||||
// propagate the dom event so the element is updated. This has to be done
|
||||
// before interpretKeyEvents: though so individual commands have a chance
|
||||
@@ -735,45 +771,53 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)insertNewline:(id)sender
|
||||
{
|
||||
if (_isEditing)
|
||||
if ([self _valueIsValid:_stringValue])
|
||||
{
|
||||
_isEditing = NO;
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
}
|
||||
// If _isEditing == YES then the target action can also be called via
|
||||
// resignFirstResponder, and it is possible that the target action
|
||||
// itself will change this textfield's responder status, so start by
|
||||
// setting the _isEditing flag to NO to prevent the target action being
|
||||
// called twice (once below and once from resignFirstResponder).
|
||||
if (_isEditing)
|
||||
{
|
||||
_isEditing = NO;
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
[self selectText:nil];
|
||||
// If there is no target action, or the sendAction call returns
|
||||
// success.
|
||||
if (![self action] || [self sendAction:[self action] to:[self target]])
|
||||
{
|
||||
[self selectAll:nil];
|
||||
}
|
||||
}
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||
}
|
||||
|
||||
- (void)insertNewlineIgnoringFieldEditor:(id)sender
|
||||
{
|
||||
var oldValue = [self stringValue];
|
||||
|
||||
[self _inputElement].value += CPNewlineCharacter;
|
||||
[self _setStringValue:[self _inputElement].value];
|
||||
|
||||
if (oldValue !== [self stringValue])
|
||||
{
|
||||
if (!_isEditing)
|
||||
{
|
||||
_isEditing = YES;
|
||||
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
|
||||
}
|
||||
[self _insertCharacterIgnoringFieldEditor:CPNewlineCharacter];
|
||||
}
|
||||
|
||||
- (void)insertTabIgnoringFieldEditor:(id)sender
|
||||
{
|
||||
var oldValue = [self stringValue];
|
||||
[self _insertCharacterIgnoringFieldEditor:CPTabCharacter];
|
||||
}
|
||||
|
||||
[self _inputElement].value += CPTabCharacter;
|
||||
[self _setStringValue:[self _inputElement].value];
|
||||
- (void)_insertCharacterIgnoringFieldEditor:(CPString)aCharacter
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
if (oldValue !== [self stringValue])
|
||||
var oldValue = _stringValue,
|
||||
range = [self selectedRange],
|
||||
element = [self _inputElement];
|
||||
|
||||
element.value = [element.value stringByReplacingCharactersInRange:[self selectedRange] withString:aCharacter];
|
||||
[self _setStringValue:element.value];
|
||||
|
||||
// NOTE: _stringValue is now the current input element value
|
||||
if (oldValue !== _stringValue)
|
||||
{
|
||||
if (!_isEditing)
|
||||
{
|
||||
@@ -783,6 +827,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)textDidBlur:(CPNotification)note
|
||||
@@ -813,15 +859,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[super textDidChange:note];
|
||||
}
|
||||
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
[self _reverseSetBinding];
|
||||
|
||||
[CPApp sendAction:anAction to:anObject from:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the string the text field.
|
||||
Returns the string in the text field.
|
||||
*/
|
||||
- (id)objectValue
|
||||
{
|
||||
@@ -830,24 +869,84 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
/*
|
||||
@ignore
|
||||
Sets the internal string value without updating the value in the input element
|
||||
Sets the internal string value without updating the value in the input element.
|
||||
This should only be invoked when the underlying text element's value has changed.
|
||||
*/
|
||||
- (void)_setStringValue:(id)aValue
|
||||
- (BOOL)_setStringValue:(CPString)aValue
|
||||
{
|
||||
[self willChangeValueForKey:@"objectValue"];
|
||||
[super setObjectValue:String(aValue)];
|
||||
[self _updatePlaceholderState];
|
||||
[self didChangeValueForKey:@"objectValue"];
|
||||
return [self _setStringValue:aValue isNewValue:YES errorDescription:nil];
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
Sets the internal string value without updating the value in the input element.
|
||||
If there is a formatter and formatting fails, returns NO. Otherwise returns YES.
|
||||
*/
|
||||
- (BOOL)_setStringValue:(CPString)aValue isNewValue:(BOOL)isNewValue errorDescription:(CPStringRef)anError
|
||||
{
|
||||
_stringValue = aValue;
|
||||
|
||||
var objectValue = aValue,
|
||||
formatter = [self formatter],
|
||||
result = YES;
|
||||
|
||||
if (formatter)
|
||||
{
|
||||
var object = nil;
|
||||
|
||||
if ([formatter getObjectValue:AT_REF(object) forString:aValue errorDescription:anError])
|
||||
objectValue = object;
|
||||
else
|
||||
{
|
||||
objectValue = undefined; // Mark the value as invalid
|
||||
result = NO;
|
||||
}
|
||||
|
||||
isNewValue |= objectValue !== [super objectValue];
|
||||
}
|
||||
|
||||
if (isNewValue)
|
||||
{
|
||||
[self willChangeValueForKey:@"objectValue"];
|
||||
[super setObjectValue:objectValue];
|
||||
[self _updatePlaceholderState];
|
||||
[self didChangeValueForKey:@"objectValue"];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
[super setObjectValue:aValue];
|
||||
|
||||
var formatter = [self formatter];
|
||||
|
||||
if (formatter)
|
||||
{
|
||||
// If there is a formatter, make sure the object value can be formatted successfully
|
||||
var formattedString = [self hasThemeState:CPThemeStateEditing] ? [formatter editingStringForObjectValue:aValue] : [formatter stringForObjectValue:aValue];
|
||||
|
||||
if (formattedString === nil)
|
||||
{
|
||||
var value = nil;
|
||||
|
||||
// Formatting failed, get an "empty" object by formatting an empty string.
|
||||
// If that fails, the value is undefined.
|
||||
if ([formatter getObjectValue:AT_REF(value) forString:@"" errorDescription:nil] === NO)
|
||||
value = undefined;
|
||||
|
||||
[super setObjectValue:value];
|
||||
}
|
||||
}
|
||||
|
||||
_stringValue = [self stringValue];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self)
|
||||
[self _inputElement].value = aValue;
|
||||
[self _inputElement].value = _stringValue;
|
||||
|
||||
#endif
|
||||
|
||||
[self _updatePlaceholderState];
|
||||
@@ -855,9 +954,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)_updatePlaceholderState
|
||||
{
|
||||
var string = [self stringValue];
|
||||
|
||||
if ((!string || string.length === 0) && ![self hasThemeState:CPThemeStateEditing])
|
||||
if ((!_stringValue || _stringValue.length === 0) && ![self hasThemeState:CPThemeStateEditing])
|
||||
[self setThemeState:CPTextFieldStatePlaceholder];
|
||||
else
|
||||
[self unsetThemeState:CPTextFieldStatePlaceholder];
|
||||
@@ -923,8 +1020,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
minSize = [self currentValueForThemeAttribute:@"min-size"],
|
||||
maxSize = [self currentValueForThemeAttribute:@"max-size"],
|
||||
lineBreakMode = [self lineBreakMode],
|
||||
text = ([self stringValue] || @" "),
|
||||
textSize = _CGSizeMakeCopy(frameSize),
|
||||
text = (_stringValue || @" "),
|
||||
textSize = CGSizeMakeCopy(frameSize),
|
||||
font = [self currentValueForThemeAttribute:@"font"];
|
||||
|
||||
textSize.width -= contentInset.left + contentInset.right;
|
||||
@@ -994,8 +1091,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return;
|
||||
|
||||
var pasteboard = [CPPasteboard generalPasteboard],
|
||||
stringValue = [self stringValue],
|
||||
stringForPasting = [stringValue substringWithRange:selectedRange];
|
||||
stringForPasting = [_stringValue substringWithRange:selectedRange];
|
||||
|
||||
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
|
||||
[pasteboard setString:stringForPasting forType:CPStringPboardType];
|
||||
@@ -1025,9 +1121,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[self deleteBackward:sender];
|
||||
|
||||
var selectedRange = [self selectedRange],
|
||||
stringValue = [self stringValue],
|
||||
pasteString = [pasteboard stringForType:CPStringPboardType],
|
||||
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
|
||||
newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
|
||||
|
||||
[self setStringValue:newValue];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)];
|
||||
@@ -1041,6 +1136,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
if ([[self window] firstResponder] !== self)
|
||||
return CPMakeRange(0, 0);
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
// we wrap this in try catch because firefox will throw an exception in certain instances
|
||||
try
|
||||
{
|
||||
@@ -1067,6 +1164,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
// fall through to the return
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return CPMakeRange(0, 0);
|
||||
}
|
||||
|
||||
@@ -1075,6 +1174,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
if (![[self window] firstResponder] === self)
|
||||
return;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var inputElement = [self _inputElement];
|
||||
|
||||
try
|
||||
@@ -1103,6 +1204,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
catch (e)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)selectAll:(id)sender
|
||||
@@ -1120,8 +1223,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
selectedRange.location += 1;
|
||||
selectedRange.length -= 1;
|
||||
|
||||
var stringValue = [self stringValue],
|
||||
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
|
||||
var newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
|
||||
|
||||
[self setStringValue:newValue];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location, 0)];
|
||||
@@ -1189,10 +1291,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (CGRect)contentRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
|
||||
if (!contentInset)
|
||||
return bounds;
|
||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"],
|
||||
contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
|
||||
bounds.origin.x += contentInset.left;
|
||||
bounds.origin.y += contentInset.top;
|
||||
@@ -1217,6 +1317,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return bounds;
|
||||
}
|
||||
|
||||
- (CGInset)borderInset
|
||||
{
|
||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"],
|
||||
borderInset = [self currentValueForThemeAttribute:@"border-inset"];
|
||||
|
||||
return CGInsetUnion(bezelInset, borderInset);
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
if (aName === "bezel-view")
|
||||
@@ -1274,7 +1382,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
string = [self placeholderString];
|
||||
else
|
||||
{
|
||||
string = [self stringValue];
|
||||
string = _stringValue;
|
||||
|
||||
if ([self isSecure])
|
||||
string = secureStringForString(string);
|
||||
|
||||
@@ -25,9 +25,10 @@
|
||||
@import <Foundation/CPKeyedUnarchiver.j>
|
||||
|
||||
|
||||
var CPThemesByName = { },
|
||||
CPThemeDefaultTheme = nil,
|
||||
CPThemeDefaultHudTheme = nil;
|
||||
var CPThemesByName = { },
|
||||
CPThemeNamesByInheritance = [],
|
||||
CPThemeDefaultTheme = nil,
|
||||
CPThemeDefaultHudTheme = nil;
|
||||
|
||||
|
||||
/*!
|
||||
@@ -76,6 +77,52 @@ var CPThemesByName = { },
|
||||
return CPThemesByName[aName];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns an array of names of all loaded themes, in the order they were loaded.
|
||||
*/
|
||||
+ (CPArray)allThemeNames
|
||||
{
|
||||
return [CPThemeNamesByInheritance copy];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the closest matching theme for a given view or view class.
|
||||
The matching proceeds as follows:
|
||||
|
||||
- The default theme class name for the class is retrieved.
|
||||
- Starting with the last loaded theme and proceeding towards the default theme,
|
||||
each theme is checked to see if it defines that theme class.
|
||||
- If the theme defines the class name, that theme is returned.
|
||||
- If no themes match, the default theme is returned.
|
||||
|
||||
@param aViewOrClass The view or view class to match with a theme
|
||||
@return The first matching theme
|
||||
*/
|
||||
+ (CPTheme)themeForView:(id)aViewOrClass
|
||||
{
|
||||
var themeClass = nil;
|
||||
|
||||
if (class_isMetaClass(aViewOrClass.isa))
|
||||
themeClass = [aViewOrClass defaultThemeClass];
|
||||
else
|
||||
themeClass = [aViewOrClass themeClass];
|
||||
|
||||
if (themeClass)
|
||||
{
|
||||
var count = CPThemeNamesByInheritance.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var theme = CPThemesByName[CPThemeNamesByInheritance[count]];
|
||||
|
||||
if ([theme._attributes containsKey:themeClass])
|
||||
return theme;
|
||||
}
|
||||
}
|
||||
|
||||
return CPThemeDefaultTheme;
|
||||
}
|
||||
|
||||
- (id)initWithName:(CPString)aName
|
||||
{
|
||||
self = [super init];
|
||||
@@ -86,6 +133,9 @@ var CPThemesByName = { },
|
||||
_attributes = [CPDictionary dictionary];
|
||||
|
||||
CPThemesByName[_name] = self;
|
||||
|
||||
if (![CPThemeNamesByInheritance containsObject:_name])
|
||||
CPThemeNamesByInheritance.push(_name);
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -299,6 +349,9 @@ var CPThemeNameKey = @"CPThemeNameKey",
|
||||
_attributes = [aCoder decodeObjectForKey:CPThemeAttributesKey];
|
||||
|
||||
CPThemesByName[_name] = self;
|
||||
|
||||
if (![CPThemeNamesByInheritance containsObject:_name])
|
||||
CPThemeNamesByInheritance.push(_name);
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -93,65 +93,69 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
return "tokenfield";
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)frame
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame])
|
||||
{
|
||||
_selectedRange = CPMakeRange(0, 0);
|
||||
|
||||
_tokenScrollView = [[CPScrollView alloc] initWithFrame:CGRectMakeZero()];
|
||||
[_tokenScrollView setHasHorizontalScroller:NO];
|
||||
[_tokenScrollView setHasVerticalScroller:NO];
|
||||
[_tokenScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
var contentView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
[contentView setAutoresizingMask:CPViewWidthSizable];
|
||||
[_tokenScrollView setDocumentView:contentView];
|
||||
|
||||
[self addSubview:_tokenScrollView];
|
||||
|
||||
_tokenIndex = 0;
|
||||
|
||||
_cachedCompletions = [];
|
||||
_completionDelay = [CPTokenField defaultCompletionDelay];
|
||||
|
||||
_tokenizingCharacterSet = [[self class] defaultTokenizingCharacterSet];
|
||||
|
||||
_autocompleteContainer = [[CPView alloc] initWithFrame:CPRectMake(0.0, 0.0, frame.size.width, 92.0)];
|
||||
[_autocompleteContainer setBackgroundColor:[_CPMenuWindow backgroundColorForBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle]];
|
||||
|
||||
_autocompleteScrollView = [[CPScrollView alloc] initWithFrame:CPRectMake(1.0, 1.0, frame.size.width - 2.0, 90.0)];
|
||||
[_autocompleteScrollView setAutohidesScrollers:YES];
|
||||
[_autocompleteScrollView setHasHorizontalScroller:NO];
|
||||
[_autocompleteContainer addSubview:_autocompleteScrollView];
|
||||
|
||||
_autocompleteView = [[CPTableView alloc] initWithFrame:CPRectMakeZero()];
|
||||
|
||||
var tableColumn = [[CPTableColumn alloc] initWithIdentifier:CPTokenFieldTableColumnIdentifier];
|
||||
[tableColumn setResizingMask:CPTableColumnAutoresizingMask];
|
||||
[_autocompleteView addTableColumn:tableColumn];
|
||||
|
||||
[_autocompleteView setDataSource:self];
|
||||
[_autocompleteView setDelegate:self];
|
||||
[_autocompleteView setAllowsMultipleSelection:NO];
|
||||
[_autocompleteView setHeaderView:nil];
|
||||
[_autocompleteView setCornerView:nil];
|
||||
[_autocompleteView setRowHeight:30.0];
|
||||
[_autocompleteView setGridStyleMask:CPTableViewSolidHorizontalGridLineMask];
|
||||
[_autocompleteView setBackgroundColor:[CPColor clearColor]];
|
||||
[_autocompleteView setGridColor:[CPColor colorWithRed:242.0 / 255.0 green:243.0 / 255.0 blue:245.0 / 255.0 alpha:1.0]];
|
||||
|
||||
[_autocompleteScrollView setDocumentView:_autocompleteView];
|
||||
|
||||
[self setBezeled:YES];
|
||||
|
||||
[self _init];
|
||||
|
||||
[self setObjectValue:[]];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
var frame = [self frame];
|
||||
|
||||
_tokenScrollView = [[CPScrollView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
[_tokenScrollView setHasHorizontalScroller:NO];
|
||||
[_tokenScrollView setHasVerticalScroller:NO];
|
||||
[_tokenScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
var contentView = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
[contentView setAutoresizingMask:CPViewWidthSizable];
|
||||
[_tokenScrollView setDocumentView:contentView];
|
||||
|
||||
[self addSubview:_tokenScrollView];
|
||||
|
||||
_cachedCompletions = [];
|
||||
|
||||
_autocompleteContainer = [[CPView alloc] initWithFrame:_CGRectMake(0.0, 0.0, frame.size.width, 92.0)];
|
||||
[_autocompleteContainer setBackgroundColor:[_CPMenuWindow backgroundColorForBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle]];
|
||||
|
||||
_autocompleteScrollView = [[CPScrollView alloc] initWithFrame:_CGRectMake(1.0, 1.0, frame.size.width - 2.0, 90.0)];
|
||||
[_autocompleteScrollView setAutohidesScrollers:YES];
|
||||
[_autocompleteScrollView setHasHorizontalScroller:NO];
|
||||
[_autocompleteContainer addSubview:_autocompleteScrollView];
|
||||
|
||||
_autocompleteView = [[CPTableView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
var tableColumn = [[CPTableColumn alloc] initWithIdentifier:CPTokenFieldTableColumnIdentifier];
|
||||
[tableColumn setResizingMask:CPTableColumnAutoresizingMask];
|
||||
[_autocompleteView addTableColumn:tableColumn];
|
||||
|
||||
[_autocompleteView setDataSource:self];
|
||||
[_autocompleteView setDelegate:self];
|
||||
[_autocompleteView setAllowsMultipleSelection:NO];
|
||||
[_autocompleteView setHeaderView:nil];
|
||||
[_autocompleteView setCornerView:nil];
|
||||
[_autocompleteView setRowHeight:30.0];
|
||||
[_autocompleteView setGridStyleMask:CPTableViewSolidHorizontalGridLineMask];
|
||||
[_autocompleteView setBackgroundColor:[CPColor clearColor]];
|
||||
[_autocompleteView setGridColor:[CPColor colorWithRed:242.0 / 255.0 green:243.0 / 255.0 blue:245.0 / 255.0 alpha:1.0]];
|
||||
|
||||
[_autocompleteScrollView setDocumentView:_autocompleteView];
|
||||
}
|
||||
|
||||
// ===============
|
||||
// = CONVENIENCE =
|
||||
// ===============
|
||||
@@ -159,12 +163,16 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
{
|
||||
var indexOfSelectedItem = 0;
|
||||
|
||||
_cachedCompletions = [self tokenField:self completionsForSubstring:[self _inputElement].value indexOfToken:_tokenIndex indexOfSelectedItem:indexOfSelectedItem];
|
||||
#if PLATFORM(DOM)
|
||||
_cachedCompletions = [self tokenField:self completionsForSubstring:[self _inputElement].value indexOfToken:0 indexOfSelectedItem:indexOfSelectedItem];
|
||||
#endif
|
||||
|
||||
[_autocompleteView selectRowIndexes:[CPIndexSet indexSetWithIndex:indexOfSelectedItem] byExtendingSelection:NO];
|
||||
[_autocompleteView reloadData];
|
||||
}
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
- (void)_autocompleteWithDOMEvent:(JSObject)DOMEvent
|
||||
{
|
||||
if (!_cachedCompletions || ![self hasThemeState:CPThemeStateAutoCompleting])
|
||||
@@ -218,6 +226,8 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
[self _autocompleteWithDOMEvent:nil];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
- (void)_selectToken:(_CPTokenFieldToken)token byExtendingSelection:(BOOL)extend
|
||||
{
|
||||
var indexOfToken = [[self _tokens] indexOfObject:token];
|
||||
@@ -368,10 +378,10 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
|
||||
[self unsetThemeState:CPThemeStateEditing];
|
||||
|
||||
[self _autocomplete];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
[self _autocomplete];
|
||||
|
||||
var element = [self _inputElement];
|
||||
|
||||
CPTokenFieldInputResigning = YES;
|
||||
@@ -654,7 +664,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
rowRect = [autocompleteView rectOfRow:index],
|
||||
owner = CPTokenFieldInputOwner;
|
||||
|
||||
if (rowRect && !CPRectContainsRect([clipView bounds], rowRect))
|
||||
if (rowRect && !CGRectContainsRect([clipView bounds], rowRect))
|
||||
[clipView scrollToPoint:[autocompleteView rectOfRow:index].origin];
|
||||
|
||||
if (aDOMEvent.keyCode === CPReturnKeyCode || aDOMEvent.keyCode === CPTabKeyCode)
|
||||
@@ -744,7 +754,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
else if (aDOMEvent.keyCode === CPDeleteKeyCode)
|
||||
{
|
||||
// Highlight the previous token if backspace was pressed in an empty input element or re-show the completions view
|
||||
if (CPTokenFieldDOMInputElement.value == @"")
|
||||
if (CPTokenFieldDOMInputElement.value.length === 0)
|
||||
{
|
||||
[self _hideCompletions];
|
||||
|
||||
@@ -864,6 +874,15 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
}
|
||||
#endif
|
||||
|
||||
// In the context of a token field, it is empty when there are no tokens
|
||||
- (void)_updatePlaceholderState
|
||||
{
|
||||
if (([[self _tokens] count] === 0) && ![self hasThemeState:CPThemeStateEditing])
|
||||
[self setThemeState:CPTextFieldStatePlaceholder];
|
||||
else
|
||||
[self unsetThemeState:CPTextFieldStatePlaceholder];
|
||||
}
|
||||
|
||||
// - (void)setTokenStyle: (NSTokenStyle) style;
|
||||
// - (NSTokenStyle)tokenStyle;
|
||||
//
|
||||
@@ -946,9 +965,9 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
// Manually sizeToFit because CPTableView's sizeToFit doesn't work properly
|
||||
[_autocompleteContainer setHidden:NO];
|
||||
var frameOrigin = [self convertPoint:[self bounds].origin toView:[_autocompleteContainer superview]];
|
||||
[_autocompleteContainer setFrameOrigin:CPPointMake(frameOrigin.x, frameOrigin.y + frame.size.height)];
|
||||
[_autocompleteContainer setFrameSize:CPSizeMake(CPRectGetWidth([self bounds]), 92.0)];
|
||||
[_autocompleteScrollView setFrameSize:CPSizeMake([_autocompleteContainer frame].size.width - 2.0, 90.0)];
|
||||
[_autocompleteContainer setFrameOrigin:_CGPointMake(frameOrigin.x, frameOrigin.y + frame.size.height)];
|
||||
[_autocompleteContainer setFrameSize:_CGSizeMake(_CGRectGetWidth([self bounds]), 92.0)];
|
||||
[_autocompleteScrollView setFrameSize:_CGSizeMake([_autocompleteContainer frame].size.width - 2.0, 90.0)];
|
||||
}
|
||||
else
|
||||
[_autocompleteContainer setHidden:YES];
|
||||
@@ -958,11 +977,11 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
return;
|
||||
|
||||
// Move each token into the right position.
|
||||
var contentRect = CGRectMakeCopy([contentView bounds]),
|
||||
var contentRect = _CGRectMakeCopy([contentView bounds]),
|
||||
contentOrigin = contentRect.origin,
|
||||
contentSize = contentRect.size,
|
||||
offset = CPPointMake(contentOrigin.x, contentOrigin.y),
|
||||
spaceBetweenTokens = CPSizeMake(2.0, 2.0),
|
||||
offset = _CGPointMake(contentOrigin.x, contentOrigin.y),
|
||||
spaceBetweenTokens = _CGSizeMake(2.0, 2.0),
|
||||
isEditing = [[self window] firstResponder] == self,
|
||||
tokenToken = [_CPTokenFieldToken new];
|
||||
|
||||
@@ -973,7 +992,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
|
||||
var fitAndFrame = function(width, height)
|
||||
{
|
||||
var r = CGRectMake(0, 0, width, height);
|
||||
var r = _CGRectMake(0, 0, width, height);
|
||||
|
||||
if (offset.x + width >= contentSize.width && offset.x > contentOrigin.x)
|
||||
{
|
||||
@@ -986,7 +1005,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
|
||||
// Make sure the frame fits.
|
||||
if (CGRectGetHeight([contentView bounds]) < offset.y + height)
|
||||
[contentView setFrame:CGRectMake(0, 0, CGRectGetWidth([_tokenScrollView bounds]), offset.y + height)];
|
||||
[contentView setFrame:_CGRectMake(0, 0, CGRectGetWidth([_tokenScrollView bounds]), offset.y + height)];
|
||||
|
||||
offset.x += width + spaceBetweenTokens.width;
|
||||
|
||||
@@ -995,6 +1014,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
|
||||
var placeEditor = function(useRemainingWidth)
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
var element = [self _inputElement],
|
||||
textWidth = 1;
|
||||
|
||||
@@ -1004,6 +1024,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
// without clipping. Since different fonts might have different sizes of "X" this
|
||||
// solution is not ideal, but it works.
|
||||
textWidth = [(element.value || @"") + "X" sizeWithFont:[self font]].width;
|
||||
|
||||
if (useRemainingWidth)
|
||||
textWidth = MAX(contentSize.width - offset.x - 1, textWidth);
|
||||
}
|
||||
@@ -1018,6 +1039,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
// When editing, always scroll to the cursor.
|
||||
if (_selectedRange.length == 0)
|
||||
[[_tokenScrollView documentView] scrollRectToVisible:inputFrame];
|
||||
#endif
|
||||
}
|
||||
|
||||
for (var i = 0, count = [tokens count]; i < count; i++)
|
||||
@@ -1044,6 +1066,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
if (isEditing && CPMaxRange(_selectedRange) >= [tokens count])
|
||||
placeEditor(true);
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
// Hide the editor if there are selected tokens, but still keep it active
|
||||
// so we can continue using our standard keyboard handling events.
|
||||
if (isEditing && _selectedRange.length)
|
||||
@@ -1051,24 +1074,27 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
[self _inputElement].style.left = "-10000px";
|
||||
[self _inputElement].focus();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Trim off any excess height downwards.
|
||||
if (CGRectGetHeight([contentView bounds]) > offset.y + tokenHeight)
|
||||
[contentView setFrame:CGRectMake(0, 0, CGRectGetWidth([_tokenScrollView bounds]), offset.y + tokenHeight)];
|
||||
[contentView setFrame:_CGRectMake(0, 0, CGRectGetWidth([_tokenScrollView bounds]), offset.y + tokenHeight)];
|
||||
|
||||
if (_shouldScrollTo !== CPScrollDestinationNone)
|
||||
{
|
||||
// Only carry out the scroll if the cursor isn't visible.
|
||||
if (!(isEditing && _selectedRange.length == 0))
|
||||
{
|
||||
|
||||
var scrollToToken = _shouldScrollTo;
|
||||
|
||||
if (scrollToToken === CPScrollDestinationLeft)
|
||||
scrollToToken = tokens[_selectedRange.location]
|
||||
else if (scrollToToken === CPScrollDestinationRight)
|
||||
scrollToToken = tokens[MAX(0, CPMaxRange(_selectedRange) - 1)];
|
||||
|
||||
[self _scrollTokenViewToVisible:scrollToToken];
|
||||
}
|
||||
|
||||
_shouldScrollTo = CPScrollDestinationNone;
|
||||
}
|
||||
}
|
||||
@@ -1123,7 +1149,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(tokenField:completionsForSubstring:indexOfToken:indexOfSelectedItem:)])
|
||||
{
|
||||
return [[self delegate] tokenField:tokenField completionsForSubstring:substring indexOfToken:_tokenIndex indexOfSelectedItem:selectedIndex];
|
||||
return [[self delegate] tokenField:tokenField completionsForSubstring:substring indexOfToken:tokenIndex indexOfSelectedItem:selectedIndex];
|
||||
}
|
||||
|
||||
return [];
|
||||
@@ -1184,11 +1210,11 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
return "tokenfield-token";
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)frame
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame])
|
||||
{
|
||||
_deleteButton = [[_CPTokenFieldTokenCloseButton alloc] initWithFrame:CPRectMakeZero()];
|
||||
_deleteButton = [[_CPTokenFieldTokenCloseButton alloc] initWithFrame:_CGRectMakeZero()];
|
||||
[self addSubview:_deleteButton];
|
||||
|
||||
[self setEditable:NO];
|
||||
@@ -1249,7 +1275,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
buttonOffset = [_deleteButton currentValueForThemeAttribute:@"offset"],
|
||||
buttonSize = [_deleteButton currentValueForThemeAttribute:@"min-size"];
|
||||
|
||||
[_deleteButton setFrame:CPRectMake(CPRectGetMaxX(frame) - buttonOffset.x, CPRectGetMinY(frame) + buttonOffset.y, buttonSize.width, buttonSize.height)];
|
||||
[_deleteButton setFrame:_CGRectMake(_CGRectGetMaxX(frame) - buttonOffset.x, _CGRectGetMinY(frame) + buttonOffset.y, buttonSize.width, buttonSize.height)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1292,3 +1318,37 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPTokenFieldTokenizingCharacterSetKey = "CPTokenFieldTokenizingCharacterSetKey",
|
||||
CPTokenFieldCompletionDelayKey = "CPTokenFieldCompletionDelay";
|
||||
|
||||
@implementation CPTokenField (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_tokenizingCharacterSet = [aCoder decodeObjectForKey:CPTokenFieldTokenizingCharacterSetKey] || [[self class] defaultTokenizingCharacterSet];
|
||||
_completionDelay = [aCoder decodeDoubleForKey:CPTokenFieldCompletionDelayKey] || [[self class] defaultCompletionDelay];
|
||||
|
||||
[self _init];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeInt:_tokenizingCharacterSet forKey:CPTokenFieldTokenizingCharacterSetKey];
|
||||
[aCoder encodeDouble:_completionDelay forKey:CPTokenFieldCompletionDelayKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1015,7 +1015,7 @@ var TOP_MARGIN = 5.0,
|
||||
_labelSize = [_labelField frame].size;
|
||||
|
||||
_minSize = CGSizeMake(MAX(_labelSize.width, minSize.width), _labelSize.height + minSize.height + LABEL_MARGIN + TOP_MARGIN);
|
||||
_maxSize = CGSizeMake(MIN(_labelSize.width, maxSize.width), 100000000.0);
|
||||
_maxSize = CGSizeMake(MAX(_labelSize.width, maxSize.width), 100000000.0);
|
||||
|
||||
[_toolbar tile];
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ var CPViewFlags = { },
|
||||
_DOMImageSizes = [];
|
||||
#endif
|
||||
|
||||
_theme = [CPTheme defaultTheme];
|
||||
_theme = [CPTheme themeForView:self];
|
||||
_themeState = CPThemeStateNormal;
|
||||
|
||||
[self setupViewFlags];
|
||||
@@ -2543,6 +2543,32 @@ setBoundsOrigin:
|
||||
return (_themeAttributes && _themeAttributes[aName] !== undefined);
|
||||
}
|
||||
|
||||
- (void)registerThemeValues:(CPArray)themeValues
|
||||
{
|
||||
for (var i = 0; i < themeValues.length; ++i)
|
||||
{
|
||||
var attributeValueState = themeValues[i],
|
||||
attribute = attributeValueState[0],
|
||||
value = attributeValueState[1],
|
||||
state = attributeValueState[2];
|
||||
|
||||
if (state)
|
||||
[self setValue:value forThemeAttribute:attribute inState:state];
|
||||
else
|
||||
[self setValue:value forThemeAttribute:attribute];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)registerThemeValues:(CPArray)themeValues inherit:(CPArray)inheritedValues
|
||||
{
|
||||
// Register inherited values first, then override those with the subtheme values.
|
||||
if (inheritedValues)
|
||||
[self registerThemeValues:inheritedValues];
|
||||
|
||||
if (themeValues)
|
||||
[self registerThemeValues:themeValues];
|
||||
}
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aViewName
|
||||
{
|
||||
return nil;
|
||||
@@ -2695,7 +2721,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
|
||||
[self setupViewFlags];
|
||||
|
||||
_theme = [CPTheme defaultTheme];
|
||||
_theme = [CPTheme themeForView:self];
|
||||
_themeClass = [aCoder decodeObjectForKey:CPViewThemeClassKey];
|
||||
_themeState = CPThemeState([aCoder decodeIntForKey:CPViewThemeStateKey]);
|
||||
_themeAttributes = {};
|
||||
|
||||
@@ -111,7 +111,8 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
|
||||
view = [self _targetView:dictionary],
|
||||
startFrame = [self _startFrame:dictionary],
|
||||
endFrame = [self _endFrame:dictionary],
|
||||
differenceFrame = _CGRectMakeZero();
|
||||
differenceFrame = _CGRectMakeZero(),
|
||||
value = [super currentValue];
|
||||
|
||||
differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x;
|
||||
differenceFrame.origin.y = endFrame.origin.y - startFrame.origin.y;
|
||||
@@ -119,19 +120,19 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
|
||||
differenceFrame.size.height = endFrame.size.height - startFrame.size.height;
|
||||
|
||||
var intermediateFrame = _CGRectMakeZero();
|
||||
intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * progress;
|
||||
intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * progress;
|
||||
intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * progress;
|
||||
intermediateFrame.size.height = startFrame.size.height + differenceFrame.size.height * progress;
|
||||
intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * value;
|
||||
intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * value;
|
||||
intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * value;
|
||||
intermediateFrame.size.height = startFrame.size.height + differenceFrame.size.height * value;
|
||||
|
||||
[view setFrame:intermediateFrame];
|
||||
|
||||
// Update the view's alpha value
|
||||
var effect = [self _effect:dictionary];
|
||||
if (effect === CPViewAnimationFadeInEffect)
|
||||
[view setAlphaValue:1.0 * progress];
|
||||
[view setAlphaValue:1.0 * value];
|
||||
else if (effect === CPViewAnimationFadeOutEffect)
|
||||
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress];
|
||||
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * value];
|
||||
|
||||
if (progress === 1.0)
|
||||
[self _targetView:view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
|
||||
|
||||
@@ -480,6 +480,7 @@ CPTexturedBackgroundWindowMask
|
||||
[self close];
|
||||
|
||||
_platformWindow = aPlatformWindow;
|
||||
[_platformWindow setTitle:_title];
|
||||
|
||||
if (wasVisible)
|
||||
[self orderFront:self];
|
||||
@@ -1359,6 +1360,7 @@ CPTexturedBackgroundWindowMask
|
||||
_title = aTitle;
|
||||
|
||||
[_windowView setTitle:aTitle];
|
||||
[_platformWindow setTitle:_title];
|
||||
|
||||
[self _synchronizeMenuBarTitleWithWindowTitle];
|
||||
}
|
||||
@@ -2928,5 +2930,6 @@ CPCustomWindowShadowStyle = 3;
|
||||
@import "_CPHUDWindowView.j"
|
||||
@import "_CPBorderlessWindowView.j"
|
||||
@import "_CPBorderlessBridgeWindowView.j"
|
||||
@import "_CPAttachedWindowView.j"
|
||||
@import "CPDragServer.j"
|
||||
@import "CPView.j"
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* _CPAttachedWindowView.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Antoine Mercadal
|
||||
* Copyright 2011 <primalmotion@archipelproject.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "_CPWindowView.j"
|
||||
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
|
||||
A custom CPWindowView that manage border and cursor
|
||||
*/
|
||||
@implementation _CPAttachedWindowView : _CPWindowView
|
||||
{
|
||||
BOOL _mouseDownPressed @accessors(getter=isMouseDownPressed, setter=setMouseDownPressed:);
|
||||
float _arrowOffsetX @accessors(property=arrowOffsetX);
|
||||
float _arrowOffsetY @accessors(property=arrowOffsetY);
|
||||
int _appearance @accessors(property=appearance);
|
||||
unsigned _preferredEdge @accessors(property=preferredEdge);
|
||||
|
||||
CPSize _cursorSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
Compute the contentView frame from a given window frame
|
||||
|
||||
@param aFrameRect the window frame
|
||||
*/
|
||||
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
var contentRect = CGRectMakeCopy(aFrameRect);
|
||||
|
||||
// @todo change border art and remove this pixel perfect adaptation
|
||||
// return CGRectInset(contentRect, 20, 20);
|
||||
|
||||
contentRect.origin.x += 18;
|
||||
contentRect.origin.y += 17;
|
||||
contentRect.size.width -= 35;
|
||||
contentRect.size.height -= 37;
|
||||
|
||||
return contentRect;
|
||||
}
|
||||
|
||||
/*!
|
||||
Compute the window frame from a given contentView frame
|
||||
|
||||
@param aContentRect the contentView frame
|
||||
*/
|
||||
+ (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
var frameRect = CGRectMakeCopy(aContentRect);
|
||||
|
||||
// @todo change border art and remove this pixel perfect adaptation
|
||||
//return CGRectOffset(frameRect, 20, 20);
|
||||
|
||||
frameRect.origin.x -= 18;
|
||||
frameRect.origin.y -= 17;
|
||||
frameRect.size.width += 35;
|
||||
frameRect.size.height += 37;
|
||||
return frameRect;
|
||||
}
|
||||
|
||||
/*!
|
||||
Initialize the _CPWindowView
|
||||
*/
|
||||
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame styleMask:aStyleMask])
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[self class]];
|
||||
_arrowOffsetX = 0.0;
|
||||
_arrowOffsetY = 0.0;
|
||||
|
||||
// @TODO: make this themable
|
||||
_useGlowingEffect = YES;
|
||||
_appearance = CPPopoverAppearanceMinimal;
|
||||
_cursorSize = CPSizeMake(15, 10);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Hide the cursor
|
||||
*/
|
||||
- (void)hideCursor
|
||||
{
|
||||
_cursorSize = CPSizeMakeZero();
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Show the cursor
|
||||
*/
|
||||
- (void)showCursor
|
||||
{
|
||||
_cursorSize = CPSizeMake(15, 10);
|
||||
[self setNeedsDisplay:YES];
|
||||
_mouseDownPressed = NO;
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the view
|
||||
*/
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
[super drawRect:aRect];
|
||||
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
radius = 5,
|
||||
arrowWidth = _cursorSize.width,
|
||||
arrowHeight = _cursorSize.height,
|
||||
strokeWidth = 1,
|
||||
strokeColor,
|
||||
shadowColor = [[CPColor blackColor] colorWithAlphaComponent:.2],
|
||||
shadowSize = CGSizeMake(0, 7),
|
||||
shadowBlur = 15,
|
||||
gradient;
|
||||
|
||||
if (_appearance == CPPopoverAppearanceMinimal)
|
||||
{
|
||||
gradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [(254.0 / 255), (254.0 / 255), (254.0 / 255), 0.93,
|
||||
(231.0 / 255), (231.0 / 255), (231.0 / 255), 0.93], [0,1], 2);
|
||||
strokeColor = [CPColor colorWithHexString:@"B8B8B8"];
|
||||
}
|
||||
else
|
||||
{
|
||||
gradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [(38.0 / 255), (38.0 / 255), (38.0 / 255), 0.93,
|
||||
(18.0 / 255), (18.0 / 255), (18.0 / 255), 0.93], [0,1], 2);
|
||||
strokeColor = [CPColor colorWithHexString:@"222222"];
|
||||
}
|
||||
|
||||
// fix rect to take care of stroke and shadow
|
||||
aRect.origin.x += strokeWidth + shadowBlur;
|
||||
aRect.origin.y += strokeWidth + (shadowBlur + shadowSize.height / 2);
|
||||
aRect.size.width -= (strokeWidth * 2) + (shadowBlur * 2);
|
||||
aRect.size.height -= (strokeWidth * 2) + (shadowBlur * 2 + shadowSize.height);
|
||||
|
||||
CGContextSetStrokeColor(context, strokeColor);
|
||||
CGContextSetLineWidth(context, strokeWidth);
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetShadowWithColor(context, shadowSize, shadowBlur, shadowColor);
|
||||
CGContextDrawLinearGradient(context, gradient, CGPointMake(CPRectGetMidX(aRect), 0.0), CGPointMake(CPRectGetMidX(aRect), aRect.size.height), 0);
|
||||
|
||||
|
||||
var xMin = _CGRectGetMinX(aRect),
|
||||
xMax = _CGRectGetMaxX(aRect),
|
||||
yMin = _CGRectGetMinY(aRect),
|
||||
yMax = _CGRectGetMaxY(aRect);
|
||||
|
||||
// draw!
|
||||
switch (_preferredEdge)
|
||||
{
|
||||
case CPMinXEdge:
|
||||
// origin ne
|
||||
CGContextMoveToPoint(context, xMin + radius, yMin);
|
||||
|
||||
// ne
|
||||
CGContextAddLineToPoint(context, xMax - radius, yMin);
|
||||
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
|
||||
|
||||
// arrow CPMinXEdge
|
||||
CGContextAddLineToPoint(context, xMax, (aRect.size.height / 2) + aRect.origin.y + _arrowOffsetY - (arrowHeight - 2));
|
||||
CGContextAddLineToPoint(context, aRect.size.width + arrowHeight + aRect.origin.x + _arrowOffsetX, (aRect.size.height / 2) + aRect.origin.y + _arrowOffsetY);
|
||||
CGContextAddLineToPoint(context, aRect.size.width + aRect.origin.x + _arrowOffsetX, (aRect.size.height / 2 + (arrowWidth / 2)) + aRect.origin.y + _arrowOffsetY);
|
||||
|
||||
// se
|
||||
CGContextAddLineToPoint(context, xMax, yMax - radius);
|
||||
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
|
||||
|
||||
// sw
|
||||
CGContextAddLineToPoint(context, xMin + radius, yMax);
|
||||
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
|
||||
|
||||
// nw
|
||||
CGContextAddLineToPoint(context, xMin, yMin + radius);
|
||||
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
|
||||
break;
|
||||
|
||||
case CPMaxXEdge:
|
||||
// origin ne
|
||||
CGContextMoveToPoint(context, xMin + radius, yMin);
|
||||
|
||||
// ne
|
||||
CGContextAddLineToPoint(context, xMax - radius, yMin);
|
||||
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
|
||||
|
||||
// se
|
||||
CGContextAddLineToPoint(context, xMax, yMax - radius);
|
||||
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
|
||||
|
||||
// sw
|
||||
CGContextAddLineToPoint(context, xMin + radius, yMax);
|
||||
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
|
||||
|
||||
// arrow CPMaxXEdge
|
||||
CGContextAddLineToPoint(context, xMin, (aRect.size.height / 2 + (arrowWidth / 2) + aRect.origin.y + _arrowOffsetY));
|
||||
CGContextAddLineToPoint(context, aRect.origin.x - arrowHeight + _arrowOffsetX, (aRect.size.height / 2) + aRect.origin.y + _arrowOffsetY);
|
||||
CGContextAddLineToPoint(context, aRect.origin.x + _arrowOffsetX, (aRect.size.height / 2 - (arrowWidth / 2) + aRect.origin.y + _arrowOffsetY));
|
||||
|
||||
// nw
|
||||
CGContextAddLineToPoint(context, xMin, yMin + radius);
|
||||
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
|
||||
break;
|
||||
|
||||
case CPMaxYEdge:
|
||||
// origin nw
|
||||
CGContextMoveToPoint(context, xMin, yMin + yMin);
|
||||
|
||||
// nw
|
||||
CGContextAddLineToPoint(context, xMin, yMin + radius);
|
||||
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
|
||||
|
||||
// arrow CPMaxYEdge
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) + aRect.origin.x + _arrowOffsetX - (arrowWidth / 2), yMin);
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) + aRect.origin.x + _arrowOffsetX, aRect.origin.y - arrowHeight + _arrowOffsetY);
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) + (arrowWidth / 2) + aRect.origin.x + _arrowOffsetX, aRect.origin.y + _arrowOffsetY);
|
||||
|
||||
// ne
|
||||
CGContextAddLineToPoint(context, xMax - radius, yMin);
|
||||
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
|
||||
|
||||
// se
|
||||
CGContextAddLineToPoint(context, xMax, yMax - radius);
|
||||
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
|
||||
|
||||
// sw
|
||||
CGContextAddLineToPoint(context, xMin + radius, yMax);
|
||||
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
|
||||
break;
|
||||
|
||||
case CPMinYEdge:
|
||||
// origin nw
|
||||
CGContextMoveToPoint(context, xMin, yMin + yMin);
|
||||
|
||||
// nw
|
||||
CGContextAddLineToPoint(context, xMin, yMin + radius);
|
||||
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
|
||||
|
||||
// ne
|
||||
CGContextAddLineToPoint(context, xMax - radius, yMin);
|
||||
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
|
||||
|
||||
// se
|
||||
CGContextAddLineToPoint(context, xMax, yMax - radius);
|
||||
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
|
||||
|
||||
// arrow CPMinYEdge
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) + (arrowWidth / 2) + aRect.origin.x + _arrowOffsetX , yMax);
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) + aRect.origin.x + _arrowOffsetX, aRect.size.height + aRect.origin.y + arrowHeight + _arrowOffsetY);
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) - (arrowWidth / 2) + aRect.origin.x + _arrowOffsetX, aRect.size.height + aRect.origin.y + _arrowOffsetY);
|
||||
|
||||
// sw
|
||||
CGContextAddLineToPoint(context, xMin + radius, yMax);
|
||||
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
|
||||
break;
|
||||
|
||||
default:
|
||||
// no computed edge means standard rounded rect
|
||||
CGContextAddPath(context, CGPathWithRoundedRectangleInRect(aRect, radius, radius, YES, YES, YES, YES));
|
||||
}
|
||||
|
||||
CGContextClosePath(context);
|
||||
|
||||
//Draw it
|
||||
CGContextStrokePath(context);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
_mouseDownPressed = YES;
|
||||
[super mouseDown:anEvent];
|
||||
}
|
||||
|
||||
- (void)mouseUp:(CPEvent)anEvent
|
||||
{
|
||||
_mouseDownPressed = NO;
|
||||
[super mouseUp:anEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* CPCibRuntimeAttributesConnector.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Aparajita Fishman.
|
||||
* Copyright 2011, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPCibConnector.j"
|
||||
|
||||
var CPCibRuntimeAttributesConnectorObjectKey = @"CPCibRuntimeAttributesConnectorObjectKey",
|
||||
CPCibRuntimeAttributesConnectorKeyPathsKey = @"CPCibRuntimeAttributesConnectorKeyPathsKey",
|
||||
CPCibRuntimeAttributesConnectorValuesKey = @"CPCibRuntimeAttributesConnectorValuesKey";
|
||||
|
||||
@implementation CPCibRuntimeAttributesConnector : CPCibConnector
|
||||
{
|
||||
id _keyPaths;
|
||||
id _values;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_source = [aCoder decodeObjectForKey:CPCibRuntimeAttributesConnectorObjectKey];
|
||||
_keyPaths = [aCoder decodeObjectForKey:CPCibRuntimeAttributesConnectorKeyPathsKey];
|
||||
_values = [aCoder decodeObjectForKey:CPCibRuntimeAttributesConnectorValuesKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_source forKey:CPCibRuntimeAttributesConnectorObjectKey];
|
||||
[aCoder encodeObject:_keyPaths forKey:CPCibRuntimeAttributesConnectorKeyPathsKey];
|
||||
[aCoder encodeObject:_values forKey:CPCibRuntimeAttributesConnectorValuesKey];
|
||||
}
|
||||
|
||||
- (void)establishConnection
|
||||
{
|
||||
var count = [_keyPaths count];
|
||||
|
||||
while (count--)
|
||||
[_source setValue:_values[count] forKeyPath:_keyPaths[count]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -61,14 +61,14 @@ var _CPCibClassSwapperClassNameKey = @"_CPCibClassSwapperClassNameKey",
|
||||
|
||||
if (!object)
|
||||
{
|
||||
CPLog.error("Unable to find class " + theClassName + " in cib file.");
|
||||
CPLog.error("Unable to find class " + theClassName + " referenced in cib file.");
|
||||
|
||||
object = [self allocObjectWithCoder:aCoder className:[aCoder decodeObjectForKey:_CPCibClassSwapperOriginalClassNameKey]];
|
||||
}
|
||||
}
|
||||
|
||||
if (!object)
|
||||
[CPException raise:CPInvalidArgumentException reason:@"Unable to find class " + theClassName + " in cib file."];
|
||||
[CPException raise:CPInvalidArgumentException reason:@"Unable to find class " + theClassName + " referenced in cib file."];
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,11 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
||||
return [[self alloc] initWithClassName:@"CPImage" resourceName:aResourceName properties:[CPDictionary dictionaryWithObject:aSize forKey:@"size"]];
|
||||
}
|
||||
|
||||
+ (id)imageResourceWithName:(CPString)aResourceName size:(CGSize)aSize bundleClass:(CPString)aBundleClass
|
||||
{
|
||||
return [[self alloc] initWithClassName:@"CPImage" resourceName:aResourceName properties:[CPDictionary dictionaryWithObjects:[aSize, aBundleClass] forKeys:[@"size", @"bundleClass"]]];
|
||||
}
|
||||
|
||||
- (id)initWithClassName:(CPString)aClassName resourceName:(CPString)aResourceName properties:(CPDictionary)properties
|
||||
{
|
||||
self = [super init];
|
||||
@@ -89,7 +94,18 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
||||
else if (_resourceName == "CPRemoveTemplate")
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
|
||||
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:_properties.valueForKey(@"size")];
|
||||
var bundleClass = _properties.valueForKey(@"bundleClass"),
|
||||
bundle = nil;
|
||||
|
||||
if (bundleClass)
|
||||
{
|
||||
bundleClass = CPClassFromString(bundleClass);
|
||||
|
||||
if (bundleClass)
|
||||
bundle = [CPBundle bundleForClass:bundleClass];
|
||||
}
|
||||
|
||||
return [[CPImage alloc] initWithContentsOfFile:[(bundle || [aCoder bundle]) pathForResource:_resourceName] size:_properties.valueForKey(@"size")];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
@import "CPCibControlConnector.j"
|
||||
@import "CPCibOutletConnector.j"
|
||||
@import "CPCibBindingConnector.j"
|
||||
@import "CPCibRuntimeAttributesConnector.j"
|
||||
|
||||
|
||||
@implementation _CPCibObjectData : CPObject
|
||||
@@ -257,11 +258,29 @@ var _CPCibObjectDataNamesKeysKey = @"_CPCibObjectDataNamesKeysKey
|
||||
_replacementObjects[[_fileOwner UID]] = anOwner;
|
||||
|
||||
var index = 0,
|
||||
count = _connections.length;
|
||||
count = _connections.length,
|
||||
runtimeAttributeConnectors = [],
|
||||
connection = nil;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var connection = _connections[index];
|
||||
connection = _connections[index];
|
||||
|
||||
if ([connection isKindOfClass:[CPCibRuntimeAttributesConnector class]])
|
||||
// Defer runtime attribute connections until after all other connections are made
|
||||
runtimeAttributeConnectors.push(connection);
|
||||
else
|
||||
{
|
||||
[connection replaceObjects:_replacementObjects];
|
||||
[connection establishConnection];
|
||||
}
|
||||
}
|
||||
|
||||
count = runtimeAttributeConnectors.length;
|
||||
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
connection = runtimeAttributeConnectors[index];
|
||||
|
||||
[connection replaceObjects:_replacementObjects];
|
||||
[connection establishConnection];
|
||||
|
||||
@@ -267,6 +267,32 @@ function CGPointFromEvent(anEvent)
|
||||
return _CGPointMake(anEvent.clientX, anEvent.clientY);
|
||||
}
|
||||
|
||||
/*!
|
||||
Combines two insets by adding their individual elements and returns the result.
|
||||
|
||||
@group CGInset
|
||||
*/
|
||||
function CGInsetUnion(lhsInset, rhsInset)
|
||||
{
|
||||
return _CGInsetMake(lhsInset.top + rhsInset.top,
|
||||
lhsInset.right + rhsInset.right,
|
||||
lhsInset.bottom + rhsInset.bottom,
|
||||
lhsInset.left + rhsInset.left);
|
||||
}
|
||||
|
||||
/*!
|
||||
Subtract one inset from another by subtracting their individual elements and returns the result.
|
||||
|
||||
@group CGInset
|
||||
*/
|
||||
function CGInsetDifference(lhsInset, rhsInset)
|
||||
{
|
||||
return _CGInsetMake(lhsInset.top - rhsInset.top,
|
||||
lhsInset.right - rhsInset.right,
|
||||
lhsInset.bottom - rhsInset.bottom,
|
||||
lhsInset.left - rhsInset.left);
|
||||
}
|
||||
|
||||
function CGInsetFromString(aString)
|
||||
{
|
||||
var numbers = aString.substr(1, aString.length - 2).split(',');
|
||||
|
||||
@@ -42,7 +42,16 @@
|
||||
#include "DOM/CPPlatformString.j"
|
||||
#else
|
||||
@implementation CPPlatformString : CPBasePlatformString
|
||||
|
||||
+ (CGSize)sizeOfString:(CPString)aString withFont:(CPFont)aFont forWidth:(float)aWidth
|
||||
{
|
||||
return _CGSizeMakeZero();
|
||||
}
|
||||
|
||||
+ (CPDictionary)metricsOfFont:(CPFont)aFont
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjectsAndKeys:0, @"ascender", 0, @"descender", 0, @"lineHeight"];
|
||||
}
|
||||
|
||||
@end
|
||||
#endif
|
||||
|
||||
@@ -32,6 +32,7 @@ var PrimaryPlatformWindow = NULL;
|
||||
CPInteger _level;
|
||||
BOOL _hasShadow;
|
||||
unsigned _shadowStyle;
|
||||
CPString _title;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
DOMWindow _DOMWindow;
|
||||
@@ -258,6 +259,21 @@ var PrimaryPlatformWindow = NULL;
|
||||
return [CPPlatform isBrowser];
|
||||
}
|
||||
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
_title = aTitle;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
if (_DOMWindow && _DOMWindow.document)
|
||||
_DOMWindow.document.title = _title;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (CPString)title
|
||||
{
|
||||
return _title;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#if PLATFORM(BROWSER)
|
||||
|
||||
@@ -534,13 +534,14 @@ var ModifierKeyCodes = [
|
||||
if (_DOMWindow)
|
||||
return _DOMWindow.focus();
|
||||
|
||||
_DOMWindow = window.open("", "_blank", "menubar=no,location=no,resizable=yes,scrollbars=no,status=no,left=" + _CGRectGetMinX(_contentRect) + ",top=" + _CGRectGetMinY(_contentRect) + ",width=" + _CGRectGetWidth(_contentRect) + ",height=" + _CGRectGetHeight(_contentRect));
|
||||
_DOMWindow = window.open("about:blank", "_blank", "menubar=no,location=no,resizable=yes,scrollbars=no,status=no,left=" + _CGRectGetMinX(_contentRect) + ",top=" + _CGRectGetMinY(_contentRect) + ",width=" + _CGRectGetWidth(_contentRect) + ",height=" + _CGRectGetHeight(_contentRect));
|
||||
|
||||
[PlatformWindows addObject:self];
|
||||
|
||||
// FIXME: cpSetFrame?
|
||||
_DOMWindow.document.write("<!DOCTYPE html><html lang='en'><head></head><body style='background-color:transparent;'></body></html>");
|
||||
_DOMWindow.document.close();
|
||||
_DOMWindow.document.title = _title;
|
||||
|
||||
if (![CPPlatform isBrowser])
|
||||
{
|
||||
|
||||
|
After Width: | Height: | Size: 146 B |
|
After Width: | Height: | Size: 141 B |
|
After Width: | Height: | Size: 219 B |
|
After Width: | Height: | Size: 490 B |
|
After Width: | Height: | Size: 160 B |
|
After Width: | Height: | Size: 361 B |
|
After Width: | Height: | Size: 694 B |
|
After Width: | Height: | Size: 221 B |
|
After Width: | Height: | Size: 146 B |
|
After Width: | Height: | Size: 141 B |
|
After Width: | Height: | Size: 219 B |
|
After Width: | Height: | Size: 407 B |
|
After Width: | Height: | Size: 160 B |
|
After Width: | Height: | Size: 348 B |
|
After Width: | Height: | Size: 622 B |
|
After Width: | Height: | Size: 217 B |
|
After Width: | Height: | Size: 422 B |
|
After Width: | Height: | Size: 527 B |
|
Before Width: | Height: | Size: 123 B After Width: | Height: | Size: 142 B |
|
After Width: | Height: | Size: 142 B |
|
After Width: | Height: | Size: 447 B |
|
After Width: | Height: | Size: 471 B |
|
Before Width: | Height: | Size: 149 B After Width: | Height: | Size: 164 B |
|
Before Width: | Height: | Size: 757 B After Width: | Height: | Size: 844 B |
|
Before Width: | Height: | Size: 735 B After Width: | Height: | Size: 908 B |
|
Before Width: | Height: | Size: 559 B After Width: | Height: | Size: 472 B |
|
Before Width: | Height: | Size: 531 B After Width: | Height: | Size: 515 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 155 B |
|
Before Width: | Height: | Size: 1004 B After Width: | Height: | Size: 130 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 160 B |
|
Before Width: | Height: | Size: 994 B After Width: | Height: | Size: 117 B |
|
Before Width: | Height: | Size: 991 B After Width: | Height: | Size: 109 B |
|
Before Width: | Height: | Size: 994 B After Width: | Height: | Size: 115 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 158 B |
|
Before Width: | Height: | Size: 997 B After Width: | Height: | Size: 124 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 159 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 160 B |
|
Before Width: | Height: | Size: 1004 B After Width: | Height: | Size: 129 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 164 B |
|
Before Width: | Height: | Size: 994 B After Width: | Height: | Size: 117 B |
|
Before Width: | Height: | Size: 991 B After Width: | Height: | Size: 109 B |
|
Before Width: | Height: | Size: 994 B After Width: | Height: | Size: 115 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 158 B |
|
Before Width: | Height: | Size: 997 B After Width: | Height: | Size: 124 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 159 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 214 B |
|
Before Width: | Height: | Size: 1012 B After Width: | Height: | Size: 133 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 234 B |
|
Before Width: | Height: | Size: 1012 B After Width: | Height: | Size: 130 B |
|
Before Width: | Height: | Size: 991 B After Width: | Height: | Size: 109 B |
|
Before Width: | Height: | Size: 1009 B After Width: | Height: | Size: 129 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 225 B |
|
Before Width: | Height: | Size: 1007 B After Width: | Height: | Size: 134 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 212 B |
@@ -762,46 +762,47 @@ var themedButtonValues = nil,
|
||||
|
||||
bezelColor = PatternColor(
|
||||
[
|
||||
["textfield-bezel-square-0.png", 3.0, 4.0],
|
||||
["textfield-bezel-square-1.png", 1.0, 4.0],
|
||||
["textfield-bezel-square-2.png", 3.0, 4.0],
|
||||
["textfield-bezel-square-3.png", 3.0, 1.0],
|
||||
["textfield-bezel-square-0.png", 6.0, 6.0],
|
||||
["textfield-bezel-square-1.png", 1.0, 6.0],
|
||||
["textfield-bezel-square-2.png", 6.0, 6.0],
|
||||
["textfield-bezel-square-3.png", 6.0, 1.0],
|
||||
["textfield-bezel-square-4.png", 1.0, 1.0],
|
||||
["textfield-bezel-square-5.png", 3.0, 1.0],
|
||||
["textfield-bezel-square-6.png", 3.0, 4.0],
|
||||
["textfield-bezel-square-7.png", 1.0, 4.0],
|
||||
["textfield-bezel-square-8.png", 3.0, 4.0]
|
||||
["textfield-bezel-square-5.png", 6.0, 1.0],
|
||||
["textfield-bezel-square-6.png", 6.0, 6.0],
|
||||
["textfield-bezel-square-7.png", 1.0, 6.0],
|
||||
["textfield-bezel-square-8.png", 6.0, 6.0]
|
||||
]),
|
||||
|
||||
bezelFocusedColor = PatternColor(
|
||||
[
|
||||
["textfield-bezel-square-focused-0.png", 7.0, 7.0],
|
||||
["textfield-bezel-square-focused-1.png", 1.0, 7.0],
|
||||
["textfield-bezel-square-focused-2.png", 7.0, 7.0],
|
||||
["textfield-bezel-square-focused-3.png", 7.0, 1.0],
|
||||
["textfield-bezel-square-focused-0.png", 6.0, 6.0],
|
||||
["textfield-bezel-square-focused-1.png", 1.0, 6.0],
|
||||
["textfield-bezel-square-focused-2.png", 6.0, 6.0],
|
||||
["textfield-bezel-square-focused-3.png", 6.0, 1.0],
|
||||
["textfield-bezel-square-focused-4.png", 1.0, 1.0],
|
||||
["textfield-bezel-square-focused-5.png", 7.0, 1.0],
|
||||
["textfield-bezel-square-focused-6.png", 7.0, 7.0],
|
||||
["textfield-bezel-square-focused-7.png", 1.0, 7.0],
|
||||
["textfield-bezel-square-focused-8.png", 7.0, 7.0]
|
||||
["textfield-bezel-square-focused-5.png", 6.0, 1.0],
|
||||
["textfield-bezel-square-focused-6.png", 6.0, 6.0],
|
||||
["textfield-bezel-square-focused-7.png", 1.0, 6.0],
|
||||
["textfield-bezel-square-focused-8.png", 6.0, 6.0]
|
||||
]),
|
||||
|
||||
bezelDisabledColor = PatternColor(
|
||||
[
|
||||
["textfield-bezel-square-disabled-0.png", 3.0, 4.0],
|
||||
["textfield-bezel-square-disabled-1.png", 1.0, 4.0],
|
||||
["textfield-bezel-square-disabled-2.png", 3.0, 4.0],
|
||||
["textfield-bezel-square-disabled-3.png", 3.0, 1.0],
|
||||
["textfield-bezel-square-disabled-0.png", 6.0, 6.0],
|
||||
["textfield-bezel-square-disabled-1.png", 1.0, 6.0],
|
||||
["textfield-bezel-square-disabled-2.png", 6.0, 6.0],
|
||||
["textfield-bezel-square-disabled-3.png", 6.0, 1.0],
|
||||
["textfield-bezel-square-disabled-4.png", 1.0, 1.0],
|
||||
["textfield-bezel-square-disabled-5.png", 3.0, 1.0],
|
||||
["textfield-bezel-square-disabled-6.png", 3.0, 4.0],
|
||||
["textfield-bezel-square-disabled-7.png", 1.0, 4.0],
|
||||
["textfield-bezel-square-disabled-8.png", 3.0, 4.0]
|
||||
["textfield-bezel-square-disabled-5.png", 6.0, 1.0],
|
||||
["textfield-bezel-square-disabled-6.png", 6.0, 6.0],
|
||||
["textfield-bezel-square-disabled-7.png", 1.0, 6.0],
|
||||
["textfield-bezel-square-disabled-8.png", 6.0, 6.0]
|
||||
]),
|
||||
|
||||
textDisabledColor = [CPColor colorWithCalibratedWhite:0.60 alpha:1.0],
|
||||
placeholderColor = [CPColor colorWithCalibratedRed:189.0 / 255.0 green:199.0 / 255.0 blue:211.0 / 255.0 alpha:1.0];
|
||||
|
||||
// Global for reuse by CPTokenField.
|
||||
// Global for reuse by subclasses
|
||||
themedTextFieldValues =
|
||||
[
|
||||
[@"vertical-alignment", CPTopVerticalTextAlignment, CPThemeStateBezeled],
|
||||
@@ -810,30 +811,37 @@ var themedButtonValues = nil,
|
||||
[@"bezel-color", bezelDisabledColor, CPThemeStateBezeled | CPThemeStateDisabled],
|
||||
[@"font", [CPFont systemFontOfSize:12.0], CPThemeStateBezeled],
|
||||
|
||||
[@"content-inset", CGInsetMake(8.0, 7.0, 5.0, 8.0), CPThemeStateBezeled],
|
||||
[@"content-inset", CGInsetMake(7.0, 7.0, 5.0, 8.0), CPThemeStateBezeled | CPThemeStateEditing],
|
||||
[@"bezel-inset", CGInsetMake(3.0, 4.0, 3.0, 4.0), CPThemeStateBezeled],
|
||||
[@"bezel-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPThemeStateBezeled | CPThemeStateEditing],
|
||||
// no border
|
||||
[@"bezel-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0)],
|
||||
[@"content-inset", CGInsetMake(2.0, 2.0, 2.0, 2.0)], // as defined in [CPTextField +themeAttributes]
|
||||
|
||||
// with border
|
||||
[@"bezel-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPThemeStateBezeled],
|
||||
[@"bezel-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPThemeStateBezeled | CPThemeStateEditing],
|
||||
[@"border-inset", CGInsetMake(3.0, 3.0, 3.0, 3.0), CPThemeStateBezeled],
|
||||
[@"content-inset", CGInsetMake(8.0, 8.0, 7.0, 8.0), CPThemeStateBezeled],
|
||||
[@"content-inset", CGInsetMake(8.0, 8.0, 7.0, 8.0), CPThemeStateBezeled | CPThemeStateEditing],
|
||||
|
||||
[@"text-color", textDisabledColor, CPThemeStateBezeled | CPThemeStateDisabled],
|
||||
[@"text-color", placeholderColor, CPTextFieldStatePlaceholder],
|
||||
|
||||
[@"line-break-mode", CPLineBreakByTruncatingTail, CPThemeStateTableDataView],
|
||||
[@"vertical-alignment", CPCenterVerticalTextAlignment, CPThemeStateTableDataView],
|
||||
[@"content-inset", CGInsetMake(0.0, 0.0, 0.0, 5.0), CPThemeStateTableDataView],
|
||||
[@"content-inset", CGInsetMake(0.0, 0.0, 0.0, 4.0), CPThemeStateTableDataView],
|
||||
|
||||
[@"text-color", [CPColor colorWithCalibratedWhite:51.0 / 255.0 alpha:1.0], CPThemeStateTableDataView],
|
||||
[@"text-color", [CPColor whiteColor], CPThemeStateTableDataView | CPThemeStateSelectedTableDataView],
|
||||
[@"font", [CPFont boldSystemFontOfSize:12.0], CPThemeStateTableDataView | CPThemeStateSelectedTableDataView],
|
||||
[@"text-color", [CPColor blackColor], CPThemeStateTableDataView | CPThemeStateEditing],
|
||||
[@"content-inset", CGInsetMake(7.0, 7.0, 5.0, 8.0), CPThemeStateTableDataView | CPThemeStateEditing],
|
||||
[@"content-inset", CGInsetMake(8.0, 8.0, 7.0, 4.0), CPThemeStateTableDataView | CPThemeStateEditing],
|
||||
[@"font", [CPFont systemFontOfSize:12.0], CPThemeStateTableDataView | CPThemeStateEditing],
|
||||
[@"bezel-inset", CGInsetMake(-2.0, -2.0, -2.0, -2.0), CPThemeStateTableDataView | CPThemeStateEditing],
|
||||
[@"bezel-inset", CGInsetMake(-1.0, -1.0, -1.0, -1.0), CPThemeStateTableDataView | CPThemeStateEditing],
|
||||
|
||||
[@"text-color", [CPColor colorWithCalibratedWhite:125.0 / 255.0 alpha:1.0], CPThemeStateTableDataView | CPThemeStateGroupRow],
|
||||
[@"text-color", [CPColor colorWithCalibratedWhite:1.0 alpha:1.0], CPThemeStateTableDataView | CPThemeStateGroupRow | CPThemeStateSelectedTableDataView],
|
||||
[@"text-shadow-color", [CPColor whiteColor], CPThemeStateTableDataView | CPThemeStateGroupRow],
|
||||
[@"text-shadow-offset", CGSizeMake(0,1), CPThemeStateTableDataView | CPThemeStateGroupRow],
|
||||
[@"text-shadow-color", [CPColor colorWithCalibratedWhite:0.0 alpha:0.6], CPThemeStateTableDataView | CPThemeStateGroupRow | CPThemeStateSelectedTableDataView],
|
||||
[@"text-shadow-color", [CPColor colorWithCalibratedWhite:0.0 alpha:0.6], CPThemeStateTableDataView | CPThemeStateGroupRow | CPThemeStateSelectedTableDataView],
|
||||
[@"font", [CPFont boldSystemFontOfSize:12.0], CPThemeStateTableDataView | CPThemeStateGroupRow]
|
||||
];
|
||||
|
||||
@@ -853,35 +861,45 @@ var themedButtonValues = nil,
|
||||
var textfield = [[CPTextField alloc] initWithFrame:CGRectMake(0.0, 0.0, 60.0, 30.0)],
|
||||
bezelColor = PatternColor(
|
||||
[
|
||||
["textfield-bezel-rounded-left.png", 13.0, 22.0],
|
||||
["textfield-bezel-rounded-center.png", 1.0, 22.0],
|
||||
["textfield-bezel-rounded-right.png", 13.0, 22.0]
|
||||
["textfield-bezel-rounded-left.png", 15.0, 30.0],
|
||||
["textfield-bezel-rounded-center.png", 1.0, 30.0],
|
||||
["textfield-bezel-rounded-right.png", 15.0, 30.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
bezelFocusedColor = PatternColor(
|
||||
[
|
||||
["textfield-bezel-rounded-focused-left.png", 17.0, 30.0],
|
||||
["textfield-bezel-rounded-focused-left.png", 15.0, 30.0],
|
||||
["textfield-bezel-rounded-focused-center.png", 1.0, 30.0],
|
||||
["textfield-bezel-rounded-focused-right.png", 17.0, 30.0]
|
||||
["textfield-bezel-rounded-focused-right.png", 15.0, 30.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
bezelDisabledColor = PatternColor(
|
||||
[
|
||||
["textfield-bezel-rounded-disabled-left.png", 15.0, 30.0],
|
||||
["textfield-bezel-rounded-disabled-center.png", 1.0, 30.0],
|
||||
["textfield-bezel-rounded-disabled-right.png", 15.0, 30.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
placeholderColor = [CPColor colorWithCalibratedRed:189.0 / 255.0 green:199.0 / 255.0 blue:211.0 / 255.0 alpha:1.0];
|
||||
|
||||
// Global for reuse by CPSearchField
|
||||
// Global for reuse by subclasses
|
||||
themedRoundedTextFieldValues =
|
||||
[
|
||||
[@"bezel-color", bezelColor, CPTextFieldStateRounded | CPThemeStateBezeled],
|
||||
[@"bezel-color", bezelFocusedColor, CPTextFieldStateRounded | CPThemeStateBezeled | CPThemeStateEditing],
|
||||
[@"bezel-color", bezelDisabledColor, CPTextFieldStateRounded | CPThemeStateBezeled | CPThemeStateDisabled],
|
||||
[@"font", [CPFont systemFontOfSize:12.0]],
|
||||
|
||||
[@"content-inset", CGInsetMake(8.0, 14.0, 6.0, 14.0), CPTextFieldStateRounded | CPThemeStateBezeled],
|
||||
[@"content-inset", CGInsetMake(7.0, 14.0, 6.0, 14.0), CPTextFieldStateRounded | CPThemeStateBezeled | CPThemeStateEditing],
|
||||
|
||||
[@"bezel-inset", CGInsetMake(4.0, 4.0, 4.0, 4.0), CPTextFieldStateRounded | CPThemeStateBezeled],
|
||||
[@"bezel-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPTextFieldStateRounded | CPThemeStateBezeled],
|
||||
[@"bezel-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPTextFieldStateRounded | CPThemeStateBezeled | CPThemeStateEditing],
|
||||
|
||||
// There is one extra empty pixel at the bottom for size compatibility with an earlier version.
|
||||
[@"content-inset", CGInsetMake(8.0, 15.0, 8.0, 15.0), CPTextFieldStateRounded | CPThemeStateBezeled],
|
||||
[@"content-inset", CGInsetMake(8.0, 15.0, 8.0, 15.0), CPTextFieldStateRounded | CPThemeStateBezeled | CPThemeStateEditing],
|
||||
|
||||
[@"text-color", placeholderColor, CPTextFieldStateRounded | CPTextFieldStatePlaceholder],
|
||||
|
||||
[@"min-size", CGSizeMake(0.0, 30.0), CPTextFieldStateRounded | CPThemeStateBezeled],
|
||||
@@ -914,11 +932,17 @@ var themedButtonValues = nil,
|
||||
|
||||
overrides =
|
||||
[
|
||||
[@"content-inset", CGInsetMake(8.0, 0.0, 4.0, 0.0)],
|
||||
// Placeholder is displayed as regular text, not tokens; requires a different inset.
|
||||
[@"content-inset", CGInsetMake(9.0, 0.0, 5.0, 2.0), CPTextFieldStatePlaceholder],
|
||||
[@"content-inset", CGInsetMake(6.0, 5.0, 5.0, 6.0), CPThemeStateBezeled],
|
||||
[@"content-inset", CGInsetMake(9.0, 7.0, 6.0, 8.0), CPThemeStateBezeled | CPTextFieldStatePlaceholder],
|
||||
// Non-bezeled token field with tokens
|
||||
[@"content-inset", CGInsetMake(5.0, 8.0, 4.0, 8.0)],
|
||||
|
||||
// Non-bezeled token field with no tokens
|
||||
[@"content-inset", CGInsetMake(7.0, 8.0, 6.0, 8.0), CPTextFieldStatePlaceholder],
|
||||
|
||||
// Bezeled token field with tokens
|
||||
[@"content-inset", CGInsetMake(6.0, 8.0, 5.0, 8.0), CPThemeStateBezeled],
|
||||
|
||||
// Bezeled token field with no tokens
|
||||
[@"content-inset", CGInsetMake(8.0, 8.0, 7.0, 8.0), CPThemeStateBezeled | CPTextFieldStatePlaceholder],
|
||||
];
|
||||
|
||||
[self registerThemeValues:overrides forView:tokenfield inherit:themedTextFieldValues];
|
||||
@@ -958,13 +982,13 @@ var themedButtonValues = nil,
|
||||
[@"text-color", textHighlightedColor, CPThemeStateHighlighted],
|
||||
|
||||
[@"bezel-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPThemeStateBezeled],
|
||||
[@"content-inset", CGInsetMake(1.0, 24.0, 2.0, 16.0), CPThemeStateBezeled],
|
||||
[@"content-inset", CGInsetMake(1.0, 23.0, 3.0, 15.0), CPThemeStateBezeled],
|
||||
|
||||
// Minimum height == maximum height since tokens are fixed height.
|
||||
[@"min-size", CGSizeMake(0.0, 19.0)],
|
||||
[@"max-size", CGSizeMake(-1.0, 19.0)],
|
||||
|
||||
[@"vertical-alignment", CPCenterTextAlignment],
|
||||
[@"vertical-alignment", CPCenterTextAlignment]
|
||||
];
|
||||
|
||||
[self registerThemeValues:themeValues forView:token];
|
||||
@@ -990,7 +1014,7 @@ var themedButtonValues = nil,
|
||||
[@"bezel-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPThemeStateBordered],
|
||||
[@"bezel-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPThemeStateBordered | CPThemeStateHighlighted],
|
||||
|
||||
[@"offset", CGPointMake(18, 6), CPThemeStateBordered]
|
||||
[@"offset", CGPointMake(17, 6), CPThemeStateBordered]
|
||||
];
|
||||
|
||||
[self registerThemeValues:themeValues forView:button];
|
||||
@@ -998,6 +1022,86 @@ var themedButtonValues = nil,
|
||||
return button;
|
||||
}
|
||||
|
||||
+ (CPComboBox)themedComboBox
|
||||
{
|
||||
var combo = [[CPComboBox alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 29.0)],
|
||||
|
||||
bezelColor = PatternColor(
|
||||
[
|
||||
["combobox-bezel-left.png", 6.0, 29.0],
|
||||
["combobox-bezel-center.png", 1.0, 29.0],
|
||||
["combobox-bezel-right.png", 24.0, 29.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
bezelFocusedColor = PatternColor(
|
||||
[
|
||||
["combobox-bezel-focused-left.png", 6.0, 29.0],
|
||||
["combobox-bezel-focused-center.png", 1.0, 29.0],
|
||||
["combobox-bezel-focused-right.png", 24.0, 29.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
bezelDisabledColor = PatternColor(
|
||||
[
|
||||
["combobox-bezel-disabled-left.png", 6.0, 29.0],
|
||||
["combobox-bezel-disabled-center.png", 1.0, 29.0],
|
||||
["combobox-bezel-disabled-right.png", 24.0, 29.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
bezelNoBorderColor = PatternColor(
|
||||
[
|
||||
["combobox-bezel-no-border-left.png", 6.0, 29.0],
|
||||
["combobox-bezel-no-border-center.png", 1.0, 29.0],
|
||||
["combobox-bezel-no-border-right.png", 24.0, 29.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
bezelNoBorderFocusedColor = PatternColor(
|
||||
[
|
||||
["combobox-bezel-no-border-focused-left.png", 6.0, 29.0],
|
||||
["combobox-bezel-no-border-focused-center.png", 1.0, 29.0],
|
||||
["combobox-bezel-no-border-focused-right.png", 24.0, 29.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
bezelNoBorderDisabledColor = PatternColor(
|
||||
[
|
||||
["combobox-bezel-no-border-disabled-left.png", 6.0, 29.0],
|
||||
["combobox-bezel-no-border-disabled-center.png", 1.0, 29.0],
|
||||
["combobox-bezel-no-border-disabled-right.png", 24.0, 29.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
overrides =
|
||||
[
|
||||
[@"bezel-color", bezelColor, CPThemeStateBezeled | CPComboBoxStateButtonBordered],
|
||||
[@"bezel-color", bezelFocusedColor, CPThemeStateBezeled | CPComboBoxStateButtonBordered | CPThemeStateEditing],
|
||||
[@"bezel-color", bezelDisabledColor, CPThemeStateBezeled | CPComboBoxStateButtonBordered | CPThemeStateDisabled],
|
||||
|
||||
[@"bezel-color", bezelNoBorderColor, CPThemeStateBezeled],
|
||||
[@"bezel-color", bezelNoBorderFocusedColor, CPThemeStateBezeled | CPThemeStateEditing],
|
||||
[@"bezel-color", bezelNoBorderDisabledColor, CPThemeStateBezeled | CPThemeStateDisabled],
|
||||
|
||||
// The right border inset has to make room for the focus ring and popup button
|
||||
[@"content-inset", CGInsetMake(8.0, 27.0, 7.0, 8.0), CPThemeStateBezeled | CPComboBoxStateButtonBordered],
|
||||
[@"content-inset", CGInsetMake(8.0, 24.0, 7.0, 8.0), CPThemeStateBezeled],
|
||||
[@"content-inset", CGInsetMake(8.0, 24.0, 7.0, 8.0), CPThemeStateBezeled | CPThemeStateEditing],
|
||||
|
||||
[@"popup-button-size", CGSizeMake(21.0, 23.0), CPThemeStateBezeled | CPComboBoxStateButtonBordered],
|
||||
[@"popup-button-size", CGSizeMake(17.0, 23.0), CPThemeStateBezeled],
|
||||
|
||||
// Because combo box uses a three-part bezel, the height is fixed
|
||||
[@"min-size", CGSizeMake(0, 29.0)],
|
||||
[@"max-size", CGSizeMake(-1, 29.0)]
|
||||
];
|
||||
|
||||
[self registerThemeValues:overrides forView:combo inherit:themedTextFieldValues];
|
||||
|
||||
return combo;
|
||||
}
|
||||
|
||||
+ (CPRadioButton)themedRadioButton
|
||||
{
|
||||
var button = [CPRadio radioWithTitle:@"Hello Friend!"],
|
||||
|
||||
@@ -225,7 +225,7 @@ var ItemSizes = { },
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)registerThemeValues:(CPArray)themeValues forView:aView inherit:(CPArray)inheritedValues
|
||||
+ (void)registerThemeValues:(CPArray)themeValues forView:(CPView)aView inherit:(CPArray)inheritedValues
|
||||
{
|
||||
// Register inherited values first, then override those with the subtheme values.
|
||||
if (inheritedValues)
|
||||
|
||||
@@ -0,0 +1,501 @@
|
||||
/*
|
||||
* _CPToolTipWindowView.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Antoine Mercadal
|
||||
* Copyright 2011 <primalmotion@archipelproject.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@import "CPButton.j"
|
||||
@import "CPWindow.j"
|
||||
|
||||
|
||||
CPClosableOnBlurWindowMask = 1 << 4;
|
||||
CPPopoverAppearanceMinimal = 0;
|
||||
CPPopoverAppearanceHUD = 1;
|
||||
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
|
||||
This is a simple attached window like the one that pops up
|
||||
when you double click on a meeting in iCal
|
||||
*/
|
||||
@implementation _CPAttachedWindow : CPWindow
|
||||
{
|
||||
BOOL _animates @accessors(property=animates);
|
||||
id _targetView @accessors(property=targetView);
|
||||
int _appearance @accessors(getter=appearance);
|
||||
|
||||
BOOL _closeOnBlur;
|
||||
BOOL _isClosed;
|
||||
BOOL _shouldPerformAnimation;
|
||||
CPButton _closeButton;
|
||||
float _animationDuration;
|
||||
}
|
||||
|
||||
/*!
|
||||
override default windowView class loader
|
||||
|
||||
@param aStyleMask the window mask
|
||||
@return the windowView class
|
||||
*/
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Class methods
|
||||
|
||||
+ (Class)_windowViewClassForStyleMask:(unsigned)aStyleMask
|
||||
{
|
||||
return _CPAttachedWindowView;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
/*!
|
||||
Create and init a _CPAttachedWindow with given size of and view
|
||||
|
||||
@param aSize the size of the attached window
|
||||
@param aView the target view
|
||||
@return ready to use _CPAttachedWindow
|
||||
*/
|
||||
+ (id)attachedWindowWithSize:(CGSize)aSize forView:(CPView)aView
|
||||
{
|
||||
return [_CPAttachedWindow attachedWindowWithSize:aSize forView:aView styleMask:nil];
|
||||
}
|
||||
|
||||
/*!
|
||||
Create and init a _CPAttachedWindow with given size of and view
|
||||
|
||||
@param aSize the size of the attached window
|
||||
@param aView the target view
|
||||
@return ready to use _CPAttachedWindow
|
||||
@param styleMask the window style mask (combine CPClosableWindowMask and CPClosableOnBlurWindowMask)
|
||||
*/
|
||||
+ (id)attachedWindowWithSize:(CGSize)aSize forView:(CPView)aView styleMask:(int)aMask
|
||||
{
|
||||
var attachedWindow = [[_CPAttachedWindow alloc] initWithContentRect:CPRectMake(0.0, 0.0, aSize.width, aSize.height) styleMask:aMask];
|
||||
|
||||
[attachedWindow attachToView:aView];
|
||||
|
||||
return attachedWindow;
|
||||
}
|
||||
|
||||
/*!
|
||||
Create and init a _CPAttachedWindow with given frame
|
||||
|
||||
@param aFrame the frame of the attached window
|
||||
@return ready to use _CPAttachedWindow
|
||||
*/
|
||||
- (id)initWithContentRect:(CGRect)aFrame
|
||||
{
|
||||
self = [self initWithContentRect:aFrame styleMask:nil]
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Create and init a _CPAttachedWindow with given frame
|
||||
|
||||
@param aFrame the frame of the attached window
|
||||
@param styleMask the window style mask (combine CPClosableWindowMask and CPClosableOnBlurWindowMask)
|
||||
@return ready to use _CPAttachedWindow
|
||||
*/
|
||||
- (id)initWithContentRect:(CGRect)aFrame styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
if (self = [super initWithContentRect:aFrame styleMask:aStyleMask])
|
||||
{
|
||||
_animates = YES;
|
||||
_animates = YES;
|
||||
_animationDuration = 150;
|
||||
_closeOnBlur = (aStyleMask & CPClosableOnBlurWindowMask);
|
||||
_isClosed = NO;
|
||||
_shouldPerformAnimation = _animates;
|
||||
|
||||
[self setLevel:CPStatusWindowLevel];
|
||||
[self setMovableByWindowBackground:YES];
|
||||
[self setHasShadow:NO];
|
||||
|
||||
_DOMElement.style.WebkitBackfaceVisibility = "hidden";
|
||||
_DOMElement.style.WebkitTransitionProperty = "-webkit-transform, opacity";
|
||||
_DOMElement.style.WebkitTransitionDuration = _animationDuration + "ms";
|
||||
|
||||
[_windowView setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Getters / Setters
|
||||
|
||||
- (void)setAppearance:(int)anAppearance
|
||||
{
|
||||
if (_appearance == anAppearance)
|
||||
return;
|
||||
|
||||
[_windowView setAppearance:anAppearance];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Observer
|
||||
|
||||
/*!
|
||||
Update the _CPAttachedWindow frame if a resize event is observed
|
||||
|
||||
*/
|
||||
- (void)observeValueForKeyPath:(CPString)aPath ofObject:(id)anObject change:(CPDictionary)theChange context:(void)aContext
|
||||
{
|
||||
if ([aPath isEqual:@"frame"])
|
||||
{
|
||||
// @TODO: not recompute everything, just compute the move offset
|
||||
var g = [_windowView preferredEdge];
|
||||
|
||||
[self positionRelativeToView:_targetView preferredEdge:g];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Notification handlers
|
||||
|
||||
- (void)_attachedWindowDidMove:(CPNotification)aNotification
|
||||
{
|
||||
if ([_windowView isMouseDownPressed])
|
||||
{
|
||||
[_targetView removeObserver:self forKeyPath:@"frame"];
|
||||
[_windowView hideCursor];
|
||||
[self setLevel:CPNormalWindowLevel];
|
||||
[_closeButton setFrameOrigin:CPPointMake(1.0, 1.0)];
|
||||
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPWindowDidMoveNotification object:self];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Utilities
|
||||
|
||||
- (CPPoint)computeOrigin:(CPView)aView preferredEdge:(int)anEdge
|
||||
{
|
||||
var frameView = [aView frame],
|
||||
currentView = aView,
|
||||
origin = [aView frameOrigin],
|
||||
lastView;
|
||||
|
||||
// if somebody succeed to use the conversion function of CPView
|
||||
// to get this working, please do.
|
||||
while (currentView = [currentView superview])
|
||||
{
|
||||
origin.x += [currentView frameOrigin].x;
|
||||
origin.y += [currentView frameOrigin].y;
|
||||
lastView = currentView;
|
||||
}
|
||||
|
||||
origin.x += [[lastView window] frame].origin.x;
|
||||
origin.y += [[lastView window] frame].origin.y;
|
||||
|
||||
// take care of the scrolling point
|
||||
if ([aView enclosingScrollView])
|
||||
{
|
||||
var offsetPoint = [[[aView enclosingScrollView] contentView] boundsOrigin];
|
||||
origin.x -= offsetPoint.x;
|
||||
origin.y -= offsetPoint.y;
|
||||
}
|
||||
|
||||
return [self computeOriginFromRect:CPRectMake(origin.x, origin.y, CPRectGetWidth(frameView), CPRectGetHeight(frameView)) preferredEdge:anEdge];
|
||||
}
|
||||
|
||||
- (CPPoint)computeOriginFromRect:(CPRect)aRect preferredEdge:(int)anEdge
|
||||
{
|
||||
var nativeRect = [[[CPApp mainWindow] platformWindow] nativeContentRect],
|
||||
originLeft = CPPointCreateCopy(aRect.origin),
|
||||
originRight = CPPointCreateCopy(aRect.origin),
|
||||
originTop = CPPointCreateCopy(aRect.origin),
|
||||
originBottom = CPPointCreateCopy(aRect.origin);
|
||||
|
||||
// CPMaxXEdge
|
||||
originRight.x += aRect.size.width;
|
||||
originRight.y += (aRect.size.height / 2.0) - (CPRectGetHeight([self frame]) / 2.0)
|
||||
|
||||
// CPMinXEdge
|
||||
originLeft.x -= CPRectGetWidth([self frame]);
|
||||
originLeft.y += (aRect.size.height / 2.0) - (CPRectGetHeight([self frame]) / 2.0)
|
||||
|
||||
// CPMaxYEdge
|
||||
originBottom.x += aRect.size.width / 2.0 - CPRectGetWidth([self frame]) / 2.0;
|
||||
originBottom.y += aRect.size.height;
|
||||
|
||||
// CPMinYEdge
|
||||
originTop.x += aRect.size.width / 2.0 - CPRectGetWidth([self frame]) / 2.0;
|
||||
originTop.y -= CPRectGetHeight([self frame]);
|
||||
|
||||
var requestedEdge = (anEdge !== nil) ? anEdge : CPMaxXEdge,
|
||||
requestedOrigin;
|
||||
|
||||
switch (requestedEdge)
|
||||
{
|
||||
case CPMaxXEdge:
|
||||
requestedOrigin = originRight;
|
||||
break;
|
||||
case CPMinXEdge:
|
||||
requestedOrigin = originLeft;
|
||||
break;
|
||||
case CPMinYEdge:
|
||||
requestedOrigin = originTop;
|
||||
break;
|
||||
case CPMaxYEdge:
|
||||
requestedOrigin = originBottom;
|
||||
break;
|
||||
}
|
||||
|
||||
var origins = [requestedOrigin, originRight, originLeft, originTop, originBottom],
|
||||
edges = [requestedEdge, CPMaxXEdge, CPMinXEdge, CPMinYEdge, CPMaxYEdge];
|
||||
|
||||
for (var i = 0; i < origins.length; i++)
|
||||
{
|
||||
var o = origins[i],
|
||||
g = edges[i];
|
||||
|
||||
[_windowView setArrowOffsetX:0];
|
||||
[_windowView setArrowOffsetY:0];
|
||||
[_windowView setPreferredEdge:g];
|
||||
|
||||
if (o.x < 0)
|
||||
{
|
||||
[_windowView setArrowOffsetX:o.x];
|
||||
o.x = 0;
|
||||
}
|
||||
if (o.x + CPRectGetWidth([self frame]) > nativeRect.size.width)
|
||||
{
|
||||
[_windowView setArrowOffsetX:(o.x + CPRectGetWidth([self frame]) - nativeRect.size.width)];
|
||||
o.x = nativeRect.size.width - CPRectGetWidth([self frame]);
|
||||
}
|
||||
if (o.y < 0)
|
||||
{
|
||||
[_windowView setArrowOffsetY:o.y];
|
||||
o.y = 0;
|
||||
}
|
||||
if (o.y + CPRectGetHeight([self frame]) > nativeRect.size.height)
|
||||
{
|
||||
[_windowView setArrowOffsetY:(CPRectGetHeight([self frame]) + o.y - nativeRect.size.height)];
|
||||
o.y = nativeRect.size.height - CPRectGetHeight([self frame]);
|
||||
}
|
||||
|
||||
switch (g)
|
||||
{
|
||||
case CPMaxXEdge:
|
||||
if (o.x >= (aRect.origin.x + aRect.size.width))
|
||||
return o;
|
||||
break;
|
||||
case CPMinXEdge:
|
||||
if ((o.x + _frame.size.width) <= aRect.origin.x)
|
||||
return o;
|
||||
break;
|
||||
case CPMaxYEdge:
|
||||
if (o.y >= (aRect.origin.y + aRect.size.height))
|
||||
return o;
|
||||
break;
|
||||
case CPMinYEdge:
|
||||
if ((o.y + _frame.size.height) <= aRect.origin.y)
|
||||
return o;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[_windowView setPreferredEdge:nil];
|
||||
return requestedOrigin;
|
||||
}
|
||||
|
||||
/*!
|
||||
Compute the frame needed to be placed to the given view
|
||||
and position the attached window according to this view (edge will be automatic)
|
||||
|
||||
@param aView the view where _CPAttachedWindow must be attached
|
||||
*/
|
||||
- (void)positionRelativeToView:(CPView)aView
|
||||
{
|
||||
[self positionRelativeToView:aView preferredEdge:nil];
|
||||
}
|
||||
|
||||
/*!
|
||||
Compute the frame needed to be placed to the given view
|
||||
and position the attached window according to this view
|
||||
|
||||
@param aView the view where _CPAttachedWindow must be attached
|
||||
@param anEdge the preferd edge to use
|
||||
*/
|
||||
- (void)positionRelativeToView:(CPView)aView preferredEdge:(int)anEdge
|
||||
{
|
||||
var point = [self computeOrigin:aView preferredEdge:anEdge];
|
||||
|
||||
[self setFrameOrigin:point];
|
||||
[_windowView showCursor];
|
||||
[self setLevel:CPStatusWindowLevel];
|
||||
[_closeButton setFrameOrigin:CPPointMake(1.0, 1.0)];
|
||||
[_windowView setNeedsDisplay:YES];
|
||||
[self makeKeyAndOrderFront:nil];
|
||||
|
||||
_targetView = aView;
|
||||
[_targetView addObserver:self forKeyPath:@"frame" options:nil context:nil];
|
||||
}
|
||||
|
||||
/*!
|
||||
Position the _CPAttachedWindow to a random point
|
||||
|
||||
@param aPoint the point where the _CPAttachedWindow will be attached
|
||||
*/
|
||||
- (void)positionRelativeToRect:(CPRect)aRect
|
||||
{
|
||||
[self positionRelativeToRect:aRect preferredEdge:nil]
|
||||
}
|
||||
|
||||
/*!
|
||||
Position the _CPAttachedWindow to a random point
|
||||
|
||||
@param aPoint the point where the _CPAttachedWindow will be attached
|
||||
@param anEdge the prefered edge
|
||||
*/
|
||||
- (void)positionRelativeToRect:(CPRect)aRect preferredEdge:(int)anEdge
|
||||
{
|
||||
var point = [self computeOriginFromRect:aRect preferredEdge:anEdge];
|
||||
|
||||
[self setFrameOrigin:point];
|
||||
[_windowView showCursor];
|
||||
[self setLevel:CPStatusWindowLevel];
|
||||
[_closeButton setFrameOrigin:CPPointMake(1.0, 1.0)];
|
||||
[_windowView setNeedsDisplay:YES];
|
||||
[self makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Actions
|
||||
|
||||
/*!
|
||||
Closes the _CPAttachedWindow
|
||||
|
||||
@param sender the sender of the action
|
||||
*/
|
||||
- (IBAction)close:(id)aSender
|
||||
{
|
||||
[self close];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Overrides
|
||||
|
||||
/*!
|
||||
Called when the window is loowing focus and close the window if CPClosableOnBlurWindowMask is setted
|
||||
*/
|
||||
- (void)resignMainWindow
|
||||
{
|
||||
if (_closeOnBlur && !_isClosed)
|
||||
{
|
||||
// set a close flag to avoid infinite loop
|
||||
_isClosed = YES;
|
||||
[self close];
|
||||
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(didAttachedWindowClose:)])
|
||||
[_delegate didAttachedWindowClose:self];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Order front the window as usual and add listener for CPWindowDidMoveNotification
|
||||
|
||||
@param sender the sender of the action
|
||||
*/
|
||||
- (IBAction)orderFront:(is)aSender
|
||||
{
|
||||
[super orderFront:aSender];
|
||||
|
||||
var tranformOrigin = "50% 100%";
|
||||
|
||||
switch ([_windowView preferredEdge])
|
||||
{
|
||||
case CPMaxYEdge:
|
||||
var posX = 50 + (([_windowView arrowOffsetX] * 100) / _frame.size.width);
|
||||
tranformOrigin = posX + "% 0%"; // 50 0
|
||||
break;
|
||||
case CPMinYEdge:
|
||||
var posX = 50 + (([_windowView arrowOffsetX] * 100) / _frame.size.width);
|
||||
tranformOrigin = posX + "% 100%"; // 50 100
|
||||
break;
|
||||
case CPMinXEdge:
|
||||
var posY = 50 + (([_windowView arrowOffsetY] * 100) / _frame.size.height);
|
||||
tranformOrigin = "100% " + posY + "%"; // 100 50
|
||||
break;
|
||||
case CPMaxXEdge:
|
||||
var posY = 50 + (([_windowView arrowOffsetY] * 100) / _frame.size.height);
|
||||
tranformOrigin = "0% "+ posY + "%"; // 0 50
|
||||
break;
|
||||
}
|
||||
|
||||
// @TODO: implement for FF
|
||||
if (_animates && _shouldPerformAnimation && typeof(_DOMElement.style.WebkitTransform) != "undefined")
|
||||
{
|
||||
_DOMElement.style.opacity = 0;
|
||||
_DOMElement.style.WebkitTransform = "scale(0)";
|
||||
_DOMElement.style.WebkitTransformOrigin = tranformOrigin;
|
||||
window.setTimeout(function(){
|
||||
_DOMElement.style.height = _frame.size.height + @"px";
|
||||
_DOMElement.style.width = _frame.size.width + @"px";
|
||||
_DOMElement.style.opacity = 1;
|
||||
_DOMElement.style.WebkitTransform = "scale(1.1)";
|
||||
var transitionEndFunction = function(){
|
||||
_DOMElement.style.WebkitTransform = "scale(1)";
|
||||
_DOMElement.removeEventListener("webkitTransitionEnd", transitionEndFunction, YES);
|
||||
};
|
||||
_DOMElement.addEventListener("webkitTransitionEnd", transitionEndFunction, YES)
|
||||
},0);
|
||||
}
|
||||
|
||||
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_attachedWindowDidMove:) name:CPWindowDidMoveNotification object:self];
|
||||
|
||||
_shouldPerformAnimation = NO;
|
||||
_isClosed = NO;
|
||||
}
|
||||
|
||||
/*!
|
||||
Close the windo with animation
|
||||
*/
|
||||
- (void)close
|
||||
{
|
||||
if (_animates && typeof(_DOMElement.style.WebkitTransform) != "undefined")
|
||||
{
|
||||
_DOMElement.style.opacity = 0;
|
||||
var transitionEndFunction = function(){
|
||||
[super close];
|
||||
_DOMElement.removeEventListener("webkitTransitionEnd", transitionEndFunction, YES);
|
||||
};
|
||||
_DOMElement.addEventListener("webkitTransitionEnd", transitionEndFunction, YES);
|
||||
}
|
||||
else
|
||||
[super close];
|
||||
|
||||
[_targetView removeObserver:self forKeyPath:@"frame"];
|
||||
|
||||
_shouldPerformAnimation = _animates;
|
||||
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(didAttachedWindowClose:)])
|
||||
[_delegate didAttachedWindowClose:self];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -288,6 +288,30 @@ var _CPimageAndTextViewFrameSizeChangedFlag = 1 << 0,
|
||||
return _textShadowOffset;
|
||||
}
|
||||
|
||||
- (CGRect)textFrame
|
||||
{
|
||||
[self layoutIfNeeded];
|
||||
|
||||
var textFrame = CGRectMakeZero();
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
if (_DOMTextElement)
|
||||
{
|
||||
var textStyle = _DOMTextElement.style;
|
||||
|
||||
textFrame.origin.y = parseInt(textStyle.top.substr(0, textStyle.top.length - 2), 10),
|
||||
textFrame.origin.x = parseInt(textStyle.left.substr(0, textStyle.left.length - 2), 10),
|
||||
textFrame.size.width = parseInt(textStyle.width.substr(0, textStyle.width.length - 2), 10),
|
||||
textFrame.size.height = parseInt(textStyle.height.substr(0, textStyle.height.length - 2), 10);
|
||||
|
||||
textFrame.size.width += _textShadowOffset.width;
|
||||
textFrame.size.height += _textShadowOffset.height;
|
||||
}
|
||||
#endif
|
||||
|
||||
return textFrame;
|
||||
}
|
||||
|
||||
- (void)setImage:(CPImage)anImage
|
||||
{
|
||||
if (_image == anImage)
|
||||
|
||||