mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-11-14 18:53:50 +00:00
Merge branch 'master' into bindings
Conflicts: AppKit/CPTableView.j AppKit/_CPCornerView.j Foundation/CPArray.j Foundation/CPKeyValueCoding.j Foundation/CPKeyValueObserving.j
This commit is contained in:
commit
6f0ca9d94c
612 files changed
+34348
-24442
No files matched your search
@@ -4,3 +4,4 @@ Build
|
||||
Demos
|
||||
./Aristo
|
||||
WebSite
|
||||
.push-package
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
[submodule "External/narwhal"]
|
||||
path = External/narwhal
|
||||
url = git://github.com/tlrobinson/narwhal.git
|
||||
[submodule "External/jack"]
|
||||
path = External/jack
|
||||
url = git://github.com/tlrobinson/jack.git
|
||||
[submodule "External/browserjs"]
|
||||
path = External/browserjs
|
||||
url = git://github.com/tlrobinson/browserjs.git
|
||||
[submodule "External/ojunit"]
|
||||
path = External/ojunit
|
||||
url = git://github.com/280north/ojunit.git
|
||||
@@ -25,6 +25,8 @@
|
||||
@import "CPAnimation.j"
|
||||
@import "CPApplication.j"
|
||||
@import "CPBezierPath.j"
|
||||
@import "CPBox.j"
|
||||
@import "CPBrowser.j"
|
||||
@import "CPButton.j"
|
||||
@import "CPButtonBar.j"
|
||||
@import "CPCheckBox.j"
|
||||
@@ -42,6 +44,7 @@
|
||||
@import "CPCompatibility.j"
|
||||
@import "CPControl.j"
|
||||
@import "CPCookie.j"
|
||||
@import "CPCursor.j"
|
||||
@import "CPDocument.j"
|
||||
@import "CPDocumentController.j"
|
||||
@import "CPEvent.j"
|
||||
@@ -55,6 +58,7 @@
|
||||
@import "CPMenu.j"
|
||||
@import "CPMenuItem.j"
|
||||
@import "CPOpenPanel.j"
|
||||
@import "CPOutlineView.j"
|
||||
@import "CPPanel.j"
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPPopUpButton.j"
|
||||
@@ -75,7 +79,9 @@
|
||||
@import "CPTextField.j"
|
||||
@import "CPToolbar.j"
|
||||
@import "CPToolbarItem.j"
|
||||
@import "CPTreeNode.j"
|
||||
@import "CPView.j"
|
||||
@import "CPViewAnimation.j"
|
||||
@import "CPViewController.j"
|
||||
@import "CPWebView.j"
|
||||
@import "CPWindow.j"
|
||||
|
||||
@@ -96,12 +96,12 @@
|
||||
return _items;
|
||||
}
|
||||
|
||||
- (void)addItem:(CPAccordionItem)anItem
|
||||
- (void)addItem:(CPAccordionViewItem)anItem
|
||||
{
|
||||
[self insertItem:anItem atIndex:_items.length];
|
||||
}
|
||||
|
||||
- (void)insertItem:(CPAccordionItem)anItem atIndex:(CPInteger)anIndex
|
||||
- (void)insertItem:(CPAccordionViewItem)anItem atIndex:(CPInteger)anIndex
|
||||
{
|
||||
// FIXME: SHIFT ITEMS RIGHT
|
||||
[_expandedItemIndexes addIndex:anIndex];
|
||||
@@ -122,7 +122,7 @@
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)removeItem:(CPAccordionItem)anItem
|
||||
- (void)removeItem:(CPAccordionViewItem)anItem
|
||||
{
|
||||
[self removeItemAtIndex:[_items indexOfObjectIdenticalTo:anItem]];
|
||||
}
|
||||
@@ -197,6 +197,20 @@
|
||||
return indexSet;
|
||||
}
|
||||
|
||||
- (void)setEnabled:(BOOL)isEnabled forItemAtIndex:(CPInteger)anIndex
|
||||
{
|
||||
var itemView = _itemViews[anIndex];
|
||||
if (!itemView)
|
||||
return;
|
||||
|
||||
if (!isEnabled)
|
||||
[self collapseItemAtIndex:anIndex];
|
||||
else
|
||||
[self expandItemAtIndex:anIndex];
|
||||
|
||||
[itemView setEnabled:isEnabled];
|
||||
}
|
||||
|
||||
- (void)_invalidateItemsStartingAtIndex:(CPInteger)anIndex
|
||||
{
|
||||
if (_dirtyItemIndex === CPNotFound)
|
||||
@@ -301,6 +315,12 @@
|
||||
[_headerView setStringValue:aLabel];
|
||||
}
|
||||
|
||||
- (void)setEnabled:(BOOL)isEnabled
|
||||
{
|
||||
if ([_headerView respondsToSelector:@selector(setEnabled:)])
|
||||
[_headerView setEnabled:isEnabled];
|
||||
}
|
||||
|
||||
- (void)setContentView:(CPView)aView
|
||||
{
|
||||
if (_contentView === aView)
|
||||
@@ -312,7 +332,7 @@
|
||||
|
||||
_contentView = aView;
|
||||
|
||||
[_contentView addObserver:self forKeyPath:@"frame" options:0 context:NULL];
|
||||
[_contentView addObserver:self forKeyPath:@"frame" options:CPKeyValueObservingOptionOld | CPKeyValueObservingOptionNew context:NULL];
|
||||
|
||||
[self addSubview:_contentView];
|
||||
|
||||
|
||||
+29
-21
@@ -116,21 +116,12 @@ var CPAlertWarningImage,
|
||||
*/
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
if (self = [super init])
|
||||
{
|
||||
_buttonCount = 0;
|
||||
_buttons = [CPArray array];
|
||||
_alertStyle = CPWarningAlertStyle;
|
||||
|
||||
_messageLabel = [[CPTextField alloc] initWithFrame:CGRectMake(57.0, 10.0, 220.0, 80.0)];
|
||||
[_messageLabel setFont:[CPFont systemFontOfSize:12.0]];
|
||||
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||
[_messageLabel setAlignment:CPJustifiedTextAlignment];
|
||||
|
||||
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)];
|
||||
|
||||
|
||||
[self setWindowStyle:nil];
|
||||
}
|
||||
|
||||
@@ -145,23 +136,37 @@ var CPAlertWarningImage,
|
||||
{
|
||||
_windowStyle = styleMask;
|
||||
|
||||
_alertPanel = [[CPPanel alloc] initWithContentRect:CGRectMake(0.0, 0.0, 300.0, 130.0) styleMask:styleMask ? styleMask | CPTitledWindowMask : CPTitledWindowMask];
|
||||
_alertPanel = [[CPPanel alloc] initWithContentRect:CGRectMake(0.0, 0.0, 400.0, 110.0) styleMask:styleMask ? styleMask | CPTitledWindowMask : CPTitledWindowMask];
|
||||
[_alertPanel setFloatingPanel:YES];
|
||||
[_alertPanel center];
|
||||
|
||||
[_messageLabel setTextColor:(styleMask == CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]];
|
||||
|
||||
|
||||
[_messageLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]];
|
||||
|
||||
var count = [_buttons count];
|
||||
for(var i=0; i < count; i++)
|
||||
{
|
||||
var button = _buttons[i];
|
||||
|
||||
[button setFrameSize:CGSizeMake([button frame].size.width, (styleMask == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
|
||||
[button setBezelStyle:(styleMask == CPHUDBackgroundWindowMask) ? CPHUDBezelStyle : CPRoundedBezelStyle];
|
||||
|
||||
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
|
||||
|
||||
[[_alertPanel contentView] addSubview:button];
|
||||
}
|
||||
|
||||
if (!_messageLabel)
|
||||
{
|
||||
var bounds = [[_alertPanel contentView] bounds];
|
||||
|
||||
_messageLabel = [[CPTextField alloc] initWithFrame:CGRectMake(57.0, 10.0, CGRectGetWidth(bounds) - 73.0, 62.0)];
|
||||
[_messageLabel setFont:[CPFont boldSystemFontOfSize:13.0]];
|
||||
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||
[_messageLabel setAlignment:CPJustifiedTextAlignment];
|
||||
[_messageLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
|
||||
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)];
|
||||
}
|
||||
|
||||
[[_alertPanel contentView] addSubview:_messageLabel];
|
||||
[[_alertPanel contentView] addSubview:_alertImageView];
|
||||
}
|
||||
@@ -251,14 +256,17 @@ var CPAlertWarningImage,
|
||||
*/
|
||||
- (void)addButtonWithTitle:(CPString)title
|
||||
{
|
||||
var button = [[CPButton alloc] initWithFrame:CGRectMake(200.0 - (_buttonCount * 90.0), 98.0, 80.0, (_windowStyle == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
|
||||
var bounds = [[_alertPanel contentView] bounds],
|
||||
button = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds) - ((_buttonCount + 1) * 90.0), CGRectGetHeight(bounds) - 34.0, 80.0, (_windowStyle == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
|
||||
|
||||
[button setTitle:title];
|
||||
[button setTarget:self];
|
||||
[button setTag:_buttonCount];
|
||||
[button setAction:@selector(_notifyDelegate:)];
|
||||
|
||||
[button setBezelStyle:(_windowStyle == CPHUDBackgroundWindowMask) ? CPHUDBezelStyle : CPRoundRectBezelStyle];
|
||||
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
|
||||
[button setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
|
||||
|
||||
[[_alertPanel contentView] addSubview:button];
|
||||
|
||||
if (_buttonCount == 0)
|
||||
@@ -298,11 +306,11 @@ var CPAlertWarningImage,
|
||||
/* @ignore */
|
||||
- (void)_notifyDelegate:(id)button
|
||||
{
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
||||
[_delegate alertDidEnd:self returnCode:[button tag]];
|
||||
|
||||
[CPApp abortModal];
|
||||
[_alertPanel close];
|
||||
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
||||
[_delegate alertDidEnd:self returnCode:[button tag]];
|
||||
}
|
||||
|
||||
@end
|
||||
+43
-8
@@ -106,8 +106,9 @@ ACTUAL_FRAME_RATE = 0;
|
||||
{
|
||||
_progress = 0.0;
|
||||
_duration = MAX(0.0, aDuration);
|
||||
_animationCurve = anAnimationCurve;
|
||||
_frameRate = 60.0;
|
||||
|
||||
[self setAnimationCurve:anAnimationCurve];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -120,7 +121,7 @@ ACTUAL_FRAME_RATE = 0;
|
||||
*/
|
||||
- (void)setAnimationCurve:(CPAnimationCurve)anAnimationCurve
|
||||
{
|
||||
switch (_animationCurve)
|
||||
switch (anAnimationCurve)
|
||||
{
|
||||
case CPAnimationEaseInOut: timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut;
|
||||
break;
|
||||
@@ -218,7 +219,7 @@ ACTUAL_FRAME_RATE = 0;
|
||||
- (void)startAnimation
|
||||
{
|
||||
// If we're already animating, or our delegate stops us, animate.
|
||||
if (_timer || _delegate && [_delegate respondsToSelector:@selector(animationShouldStart)] && ![_delegate animationShouldStart:self])
|
||||
if (_timer || _delegate && [_delegate respondsToSelector:@selector(animationShouldStart:)] && ![_delegate animationShouldStart:self])
|
||||
return;
|
||||
|
||||
if (_progress === 1.0)
|
||||
@@ -300,13 +301,47 @@ ACTUAL_FRAME_RATE = 0;
|
||||
*/
|
||||
- (float)currentValue
|
||||
{
|
||||
var t = [self currentProgress];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
|
||||
return [_delegate animation:self valueForProgress:_progress];
|
||||
return [_delegate animation:self valueForProgress:t];
|
||||
|
||||
if (_animationCurve == CPAnimationLinear)
|
||||
return _progress;
|
||||
|
||||
alert("IMPLEMENT ANIMATION CURVES!!!");
|
||||
var c1 = [],
|
||||
c2 = [];
|
||||
|
||||
[_timingFunction getControlPointAtIndex:1 values:c1];
|
||||
[_timingFunction getControlPointAtIndex:2 values:c2];
|
||||
|
||||
return CubicBezierAtTime(t,c1[0],c1[1],c2[0],c2[1],_duration);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// currently used function to determine time
|
||||
// 1:1 conversion to js from webkit source files
|
||||
// UnitBezier.h, WebCore_animation_AnimationBase.cpp
|
||||
var CubicBezierAtTime = function CubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration)
|
||||
{
|
||||
var ax=0,bx=0,cx=0,ay=0,by=0,cy=0;
|
||||
// `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
|
||||
function sampleCurveX(t) {return ((ax*t+bx)*t+cx)*t;};
|
||||
function sampleCurveY(t) {return ((ay*t+by)*t+cy)*t;};
|
||||
function sampleCurveDerivativeX(t) {return (3.0*ax*t+2.0*bx)*t+cx;};
|
||||
// The epsilon value to pass given that the animation is going to run over |duration| seconds. The longer the animation, the more precision is needed in the timing function result to avoid ugly discontinuities.
|
||||
function solveEpsilon(duration) {return 1.0/(200.0*duration);};
|
||||
function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));};
|
||||
// Given an x value, find a parametric value it came from.
|
||||
function solveCurveX(x,epsilon) {var t0,t1,t2,x2,d2,i;
|
||||
function fabs(n) {if(n>=0) {return n;}else {return 0-n;}};
|
||||
// First try a few iterations of Newton's method -- normally very fast.
|
||||
for(t2=x, i=0; i<8; i++) {x2=sampleCurveX(t2)-x; if(fabs(x2)<epsilon) {return t2;} d2=sampleCurveDerivativeX(t2); if(fabs(d2)<1e-6) {break;} t2=t2-x2/d2;}
|
||||
// Fall back to the bisection method for reliability.
|
||||
t0=0.0; t1=1.0; t2=x; if(t2<t0) {return t0;} if(t2>t1) {return t1;}
|
||||
while(t0<t1) {x2=sampleCurveX(t2); if(fabs(x2-x)<epsilon) {return t2;} if(x>x2) {t0=t2;}else {t1=t2;} t2=(t1-t0)*.5+t0;}
|
||||
return t2; // Failure.
|
||||
};
|
||||
// Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
|
||||
cx=3.0*p1x; bx=3.0*(p2x-p1x)-cx; ax=1.0-cx-bx; cy=3.0*p1y; by=3.0*(p2y-p1y)-cy; ay=1.0-cy-by;
|
||||
// Convert from input time to parametric value in curve, then from that to output time.
|
||||
return solve(t, solveEpsilon(duration));
|
||||
};
|
||||
+392
-103
@@ -31,6 +31,7 @@
|
||||
@import "CPCibLoading.j"
|
||||
@import "CPPlatform.j"
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
var CPMainCibFile = @"CPMainCibFile",
|
||||
CPMainCibFileHumanFriendly = @"Main cib file base name";
|
||||
@@ -39,6 +40,15 @@ CPApp = nil;
|
||||
|
||||
CPApplicationWillFinishLaunchingNotification = @"CPApplicationWillFinishLaunchingNotification";
|
||||
CPApplicationDidFinishLaunchingNotification = @"CPApplicationDidFinishLaunchingNotification";
|
||||
CPApplicationWillTerminateNotification = @"CPApplicationWillTerminateNotification";
|
||||
CPApplicationWillBecomeActiveNotification = @"CPApplicationWillBecomeActiveNotification";
|
||||
CPApplicationDidBecomeActiveNotification = @"CPApplicationDidBecomeActiveNotification";
|
||||
CPApplicationWillResignActiveNotification = @"CPApplicationWillResignActiveNotification";
|
||||
CPApplicationDidResignActiveNotification = @"CPApplicationDidResignActiveNotification";
|
||||
|
||||
CPTerminateNow = YES;
|
||||
CPTerminateCancel = NO;
|
||||
CPTerminateLater = -1; // not currently supported
|
||||
|
||||
CPRunStoppedResponse = -1000;
|
||||
CPRunAbortedResponse = -1001;
|
||||
@@ -78,6 +88,8 @@ CPRunContinuesResponse = -1002;
|
||||
CPArray _windows;
|
||||
CPWindow _keyWindow;
|
||||
CPWindow _mainWindow;
|
||||
CPWindow _previousKeyWindow;
|
||||
CPWindow _previousMainWindow;
|
||||
|
||||
CPMenu _mainMenu;
|
||||
CPDocumentController _documentController;
|
||||
@@ -87,10 +99,15 @@ CPRunContinuesResponse = -1002;
|
||||
//
|
||||
id _delegate;
|
||||
BOOL _finishedLaunching;
|
||||
BOOL _isActive;
|
||||
|
||||
CPDictionary _namedArgs;
|
||||
CPArray _args;
|
||||
CPString _fullArgsString;
|
||||
|
||||
CPImage _applicationIconImage;
|
||||
|
||||
CPPanel _aboutPanel;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -130,14 +147,14 @@ CPRunContinuesResponse = -1002;
|
||||
[_mainMenu setAutoenablesItems:NO];
|
||||
|
||||
var bundle = [CPBundle bundleForClass:[CPApplication class]],
|
||||
newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"N"];
|
||||
newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"n"];
|
||||
|
||||
[newMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/New.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||
[newMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/NewHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||
|
||||
[_mainMenu addItem:newMenuItem];
|
||||
|
||||
var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"O"];
|
||||
var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"o"];
|
||||
|
||||
[openMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Open.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||
[openMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/OpenHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||
@@ -150,7 +167,7 @@ CPRunContinuesResponse = -1002;
|
||||
[saveMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Save.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||
[saveMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/SaveHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||
|
||||
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"S"]];
|
||||
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"s"]];
|
||||
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:nil]];
|
||||
|
||||
[saveMenuItem setSubmenu:saveMenu];
|
||||
@@ -169,9 +186,9 @@ CPRunContinuesResponse = -1002;
|
||||
[editMenu addItem:undoMenuItem];
|
||||
[editMenu addItem:redoMenuItem];
|
||||
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"X"]],
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"C"]],
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"V"]];
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"]],
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]],
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"]];
|
||||
|
||||
[editMenuItem setSubmenu:editMenu];
|
||||
[editMenuItem setHidden:YES];
|
||||
@@ -196,37 +213,46 @@ CPRunContinuesResponse = -1002;
|
||||
{
|
||||
if (_delegate == aDelegate)
|
||||
return;
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter],
|
||||
delegateNotifications =
|
||||
[
|
||||
CPApplicationWillFinishLaunchingNotification, @selector(applicationWillFinishLaunching:),
|
||||
CPApplicationDidFinishLaunchingNotification, @selector(applicationDidFinishLaunching:),
|
||||
CPApplicationWillBecomeActiveNotification, @selector(applicationWillBecomeActive:),
|
||||
CPApplicationDidBecomeActiveNotification, @selector(applicationDidBecomeActive:),
|
||||
CPApplicationWillResignActiveNotification, @selector(applicationWillResignActive:),
|
||||
CPApplicationDidResignActiveNotification, @selector(applicationDidResignActive:),
|
||||
CPApplicationWillTerminateNotification, @selector(applicationWillTerminate:)
|
||||
],
|
||||
count = [delegateNotifications count];
|
||||
|
||||
if (_delegate)
|
||||
{
|
||||
[defaultCenter
|
||||
removeObserver:_delegate
|
||||
name:CPApplicationWillFinishLaunchingNotification
|
||||
object:self];
|
||||
var index = 0;
|
||||
|
||||
[defaultCenter
|
||||
removeObserver:_delegate
|
||||
name:CPApplicationDidFinishLaunchingNotification
|
||||
object:self];
|
||||
for (; index < count; index += 2)
|
||||
{
|
||||
var notificationName = delegateNotifications[index],
|
||||
selector = delegateNotifications[index + 1];
|
||||
|
||||
if ([_delegate respondsToSelector:selector])
|
||||
[defaultCenter removeObserver:_delegate name:notificationName object:self];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_delegate = aDelegate;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(applicationWillFinishLaunching:)])
|
||||
[defaultCenter
|
||||
addObserver:_delegate
|
||||
selector:@selector(applicationWillFinishLaunching:)
|
||||
name:CPApplicationWillFinishLaunchingNotification
|
||||
object:self];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(applicationDidFinishLaunching:)])
|
||||
[defaultCenter
|
||||
addObserver:_delegate
|
||||
selector:@selector(applicationDidFinishLaunching:)
|
||||
name:CPApplicationDidFinishLaunchingNotification
|
||||
object:self];
|
||||
|
||||
var index = 0;
|
||||
|
||||
for (; index < count; index += 2)
|
||||
{
|
||||
var notificationName = delegateNotifications[index],
|
||||
selector = delegateNotifications[index + 1];
|
||||
|
||||
if ([_delegate respondsToSelector:selector])
|
||||
[defaultCenter addObserver:_delegate selector:selector name:notificationName object:self];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -245,6 +271,14 @@ CPRunContinuesResponse = -1002;
|
||||
*/
|
||||
- (void)finishLaunching
|
||||
{
|
||||
// At this point we clear the window.status to eliminate Safari's "Cancelled" error message
|
||||
// The message shouldn't be displayed, because only an XHR is cancelled, but it is a usability issue.
|
||||
// We do it here so that applications can change it in willFinish or didFinishLaunching
|
||||
window.status = " ";
|
||||
|
||||
// We also want to set the default cursor on the body, so that buttons and things don't have an iBeam
|
||||
[[CPCursor arrowCursor] set];
|
||||
|
||||
var bundle = [CPBundle mainBundle],
|
||||
types = [bundle objectForInfoDictionaryKey:@"CPBundleDocumentTypes"];
|
||||
|
||||
@@ -270,20 +304,22 @@ CPRunContinuesResponse = -1002;
|
||||
postNotificationName:CPApplicationWillFinishLaunchingNotification
|
||||
object:self];
|
||||
|
||||
var filename = window.cpOpeningFilename && window.cpOpeningFilename(),
|
||||
needsUntitled = !!_documentController;
|
||||
var needsUntitled = !!_documentController,
|
||||
URLStrings = window.cpOpeningURLStrings && window.cpOpeningURLStrings(),
|
||||
index = 0,
|
||||
count = [URLStrings count];
|
||||
|
||||
if ([filename length])
|
||||
{
|
||||
needsUntitled = ![self _openFile:filename];
|
||||
}
|
||||
for (; index < count; ++index)
|
||||
needsUntitled = ![self _openURL:[CPURL URLWithString:URLStrings[index]]] || needsUntitled;
|
||||
|
||||
if (needsUntitled && [_delegate respondsToSelector: @selector(applicationShouldOpenUntitledFile:)])
|
||||
if (needsUntitled && [_delegate respondsToSelector:@selector(applicationShouldOpenUntitledFile:)])
|
||||
needsUntitled = [_delegate applicationShouldOpenUntitledFile:self];
|
||||
|
||||
if (needsUntitled)
|
||||
[_documentController newDocument:self];
|
||||
|
||||
|
||||
[_documentController _updateRecentDocumentsMenu];
|
||||
|
||||
[defaultCenter
|
||||
postNotificationName:CPApplicationDidFinishLaunchingNotification
|
||||
object:self];
|
||||
@@ -295,7 +331,141 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
- (void)terminate:(id)aSender
|
||||
{
|
||||
[CPPlatform terminateApplication];
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPApplicationWillTerminateNotification
|
||||
object:self];
|
||||
|
||||
if (![CPPlatform isBrowser])
|
||||
{
|
||||
[[CPDocumentController sharedDocumentController] closeAllDocumentsWithDelegate:self
|
||||
didCloseAllSelector:@selector(_documentController:didCloseAll:context:)
|
||||
contextInfo:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
[[[self keyWindow] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setApplicationIconImage:(CPImage)anImage
|
||||
{
|
||||
_applicationIconImage = anImage;
|
||||
}
|
||||
|
||||
- (CPImage)applicationIconImage
|
||||
{
|
||||
if (_applicationIconImage)
|
||||
return _applicationIconImage;
|
||||
|
||||
var imagePath = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPApplicationIcon"];
|
||||
if (imagePath)
|
||||
_applicationIconImage = [[CPImage alloc] initWithContentsOfFile:imagePath];
|
||||
|
||||
return _applicationIconImage;
|
||||
}
|
||||
|
||||
- (void)orderFrontStandardAboutPanel:(id)sender
|
||||
{
|
||||
[self orderFrontStandardAboutPanelWithOptions:nil];
|
||||
}
|
||||
|
||||
- (void)orderFrontStandardAboutPanelWithOptions:(CPDictionary)options
|
||||
{
|
||||
if (!_aboutPanel)
|
||||
{
|
||||
var mainInfo = [[CPBundle mainBundle] infoDictionary],
|
||||
applicationTitle = [options objectForKey:"ApplicationName"] || [mainInfo objectForKey:@"CPBundleName"],
|
||||
applicationIcon = [options objectForKey:@"ApplicationIcon"] || [self applicationIconImage],
|
||||
version = [options objectForKey:@"Version"] || [mainInfo objectForKey:@"CPBundleVersion"],
|
||||
applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"],
|
||||
copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"];
|
||||
|
||||
var aboutPanelController = [[CPWindowController alloc] initWithWindowCibName:@"AboutPanel"],
|
||||
aboutPanel = [aboutPanelController window],
|
||||
contentView = [aboutPanel contentView],
|
||||
imageView = [contentView viewWithTag:1],
|
||||
applicationLabel = [contentView viewWithTag:2],
|
||||
versionLabel = [contentView viewWithTag:3],
|
||||
copyrightLabel = [contentView viewWithTag:4],
|
||||
standardPath = [[CPBundle bundleForClass:[self class]] pathForResource:@"standardApplicationIcon.png"];
|
||||
|
||||
// FIXME move this into the CIB eventually
|
||||
[applicationLabel setFont:[CPFont boldSystemFontOfSize:14.0]];
|
||||
[applicationLabel setAlignment:CPCenterTextAlignment];
|
||||
[versionLabel setAlignment:CPCenterTextAlignment];
|
||||
[copyrightLabel setAlignment:CPCenterTextAlignment];
|
||||
|
||||
[imageView setImage:applicationIcon || [[CPImage alloc] initWithContentsOfFile:standardPath
|
||||
size:CGSizeMake(256, 256)]];
|
||||
|
||||
[applicationLabel setStringValue:applicationTitle || ""];
|
||||
|
||||
if (applicationVersion && version)
|
||||
[versionLabel setStringValue:@"Version " + applicationVersion + " (" + version + ")"];
|
||||
else if (applicationVersion || version)
|
||||
[versionLabel setStringValue:@"Version " + (applicationVersion || version)];
|
||||
else
|
||||
[versionLabel setStringValue:@""];
|
||||
|
||||
[copyrightLabel setStringValue:copyright || ""];
|
||||
[aboutPanel center];
|
||||
|
||||
_aboutPanel = aboutPanel;
|
||||
}
|
||||
|
||||
[_aboutPanel orderFront:self];
|
||||
}
|
||||
|
||||
|
||||
- (void)_documentController:(NSDocumentController *)docController didCloseAll:(BOOL)didCloseAll context:(Object)info
|
||||
{
|
||||
// callback method for terminate:
|
||||
if (didCloseAll)
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(applicationShouldTerminate:)])
|
||||
[self replyToApplicationShouldTerminate:[_delegate applicationShouldTerminate:self]];
|
||||
else
|
||||
[self replyToApplicationShouldTerminate:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)replyToApplicationShouldTerminate:(BOOL)terminate
|
||||
{
|
||||
if (terminate == CPTerminateNow)
|
||||
{
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillTerminateNotification object:self];
|
||||
[CPPlatform terminateApplication];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)activateIgnoringOtherApps:(BOOL)shouldIgnoreOtherApps
|
||||
{
|
||||
[self _willBecomeActive];
|
||||
|
||||
[CPPlatform activateIgnoringOtherApps:shouldIgnoreOtherApps];
|
||||
_isActive = YES;
|
||||
|
||||
[self _willResignActive];
|
||||
}
|
||||
|
||||
- (void)deactivate
|
||||
{
|
||||
[self _willResignActive];
|
||||
|
||||
[CPPlatform deactivate];
|
||||
_isActive = NO;
|
||||
|
||||
[self _didResignActive];
|
||||
}
|
||||
|
||||
- (void)isActive
|
||||
{
|
||||
return _isActive;
|
||||
}
|
||||
|
||||
- (void)hideOtherApplications:(id)aSender
|
||||
{
|
||||
[CPPlatform hideOtherApplications:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -410,10 +580,8 @@ CPRunContinuesResponse = -1002;
|
||||
/* @ignore */
|
||||
- (BOOL)_handleKeyEquivalent:(CPEvent)anEvent
|
||||
{
|
||||
if ([_mainMenu performKeyEquivalent:anEvent])
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
return [[self keyWindow] performKeyEquivalent:anEvent] ||
|
||||
[_mainMenu performKeyEquivalent:anEvent];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -424,12 +592,27 @@ CPRunContinuesResponse = -1002;
|
||||
{
|
||||
_currentEvent = anEvent;
|
||||
|
||||
var willPropagate = [[[anEvent window] platformWindow] _willPropagateCurrentDOMEvent];
|
||||
|
||||
// temporarily pretend we won't propagate the event. we'll restore the saved value later
|
||||
// we do this outside the if so that changes user code might make in _handleKeyEquiv. are preserved
|
||||
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||
|
||||
// Check if this is a candidate for key equivalent...
|
||||
if ([anEvent type] == CPKeyDown &&
|
||||
[anEvent modifierFlags] & (CPCommandKeyMask | CPControlKeyMask) &&
|
||||
[[anEvent characters] length] > 0 &&
|
||||
[self _handleKeyEquivalent:anEvent])
|
||||
if ([anEvent _couldBeKeyEquivalent] && [self _handleKeyEquivalent:anEvent])
|
||||
{
|
||||
var characters = [anEvent characters],
|
||||
modifierFlags = [anEvent modifierFlags];
|
||||
|
||||
// Unconditionally propagate on these keys to solve browser copy paste bugs
|
||||
if ((characters == "c" || characters == "x" || characters == "v") && (modifierFlags & CPPlatformActionKeyMask))
|
||||
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// if we make it this far, then restore the original willPropagate value
|
||||
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:willPropagate];
|
||||
|
||||
if (_eventListeners.length)
|
||||
{
|
||||
@@ -482,6 +665,19 @@ CPRunContinuesResponse = -1002;
|
||||
return _windows;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns an array of visible CPWindow objects, ordered by their front to back order on the screen.
|
||||
*/
|
||||
- (CPArray)orderedWindows
|
||||
{
|
||||
return CPWindowObjectList();
|
||||
}
|
||||
|
||||
- (void)hide:(id)aSender
|
||||
{
|
||||
[CPPlatform hide:self];
|
||||
}
|
||||
|
||||
// Accessing the Main Menu
|
||||
/*!
|
||||
Returns the application's main menu
|
||||
@@ -516,16 +712,6 @@ CPRunContinuesResponse = -1002;
|
||||
[[CPColorPanel sharedColorPanel] orderFront:self];
|
||||
}
|
||||
|
||||
- (void)orderFrontStandardAboutPanel:(id)aSender
|
||||
{
|
||||
[self orderFrontStandardAboutPanelWithOptions:nil];
|
||||
}
|
||||
|
||||
- (void)orderFrontStandardAboutPanelWithOptions:(CPDictionary)aDictionary
|
||||
{
|
||||
// FIXME: Implement.
|
||||
}
|
||||
|
||||
// Posting Actions
|
||||
/*!
|
||||
Tries to perform the action with an argument. Performs
|
||||
@@ -564,7 +750,7 @@ CPRunContinuesResponse = -1002;
|
||||
- (BOOL)sendAction:(SEL)anAction to:(id)aTarget from:(id)aSender
|
||||
{
|
||||
var target = [self targetForAction:anAction to:aTarget from:aSender];
|
||||
|
||||
|
||||
if (!target)
|
||||
return NO;
|
||||
|
||||
@@ -640,12 +826,11 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
if ([windowController respondsToSelector:anAction])
|
||||
return windowController;
|
||||
|
||||
|
||||
var theDocument = [windowController document];
|
||||
|
||||
if (theDocument != delegate && [theDocument respondsToSelector:anAction])
|
||||
if (theDocument !== delegate && [theDocument respondsToSelector:anAction])
|
||||
return theDocument;
|
||||
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -654,7 +839,7 @@ CPRunContinuesResponse = -1002;
|
||||
Checks for a target in the following order:
|
||||
<ol>
|
||||
<li>a responder from the key window</li>
|
||||
<li>a responder frmo the main window</li>
|
||||
<li>a responder from the main window</li>
|
||||
<li>the CPApplication instance</li>
|
||||
<li>the application delegate</li>
|
||||
<li>the document controller</li>
|
||||
@@ -693,8 +878,6 @@ CPRunContinuesResponse = -1002;
|
||||
- (void)setCallback:(Function)aCallback forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
|
||||
{
|
||||
_eventListeners.push(_CPEventListenerMake(aMask, aCallback));
|
||||
|
||||
if (_eventListeners.length == 3) objj_debug_print_backtrace();
|
||||
}
|
||||
|
||||
- (CPEvent)setTarget:(id)aTarget selector:(SEL)aSelector forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
|
||||
@@ -719,12 +902,43 @@ CPRunContinuesResponse = -1002;
|
||||
*/
|
||||
- (void)beginSheet:(CPWindow)aSheet modalForWindow:(CPWindow)aWindow modalDelegate:(id)aModalDelegate didEndSelector:(SEL)aDidEndSelector contextInfo:(id)aContextInfo
|
||||
{
|
||||
var styleMask = [aSheet styleMask];
|
||||
if (!(styleMask & CPDocModalWindowMask))
|
||||
{
|
||||
[CPException raise:CPInternalInconsistencyException reason:@"Currently only CPDocModalWindowMask style mask is supported for attached sheets"];
|
||||
return;
|
||||
}
|
||||
|
||||
[aWindow orderFront:self];
|
||||
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
|
||||
}
|
||||
|
||||
- (void)endSheet:(CPWindow)sheet returnCode:(int)returnCode
|
||||
{
|
||||
var count = [_windows count];
|
||||
|
||||
while (--count >= 0)
|
||||
{
|
||||
var aWindow = [_windows objectAtIndex:count];
|
||||
var context = aWindow._sheetContext;
|
||||
|
||||
if (context != nil && context["sheet"] === sheet)
|
||||
{
|
||||
context["returnCode"] = returnCode;
|
||||
[aWindow _detachSheetWindow];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)endSheet:(CPWindow)sheet
|
||||
{
|
||||
[self endSheet:sheet returnCode:0];
|
||||
}
|
||||
|
||||
- (CPArray)arguments
|
||||
{
|
||||
if(_fullArgsString != window.location.hash)
|
||||
if(_fullArgsString !== window.location.hash)
|
||||
[self _reloadArguments];
|
||||
|
||||
return _args;
|
||||
@@ -757,12 +971,18 @@ CPRunContinuesResponse = -1002;
|
||||
- (void)_reloadArguments
|
||||
{
|
||||
_fullArgsString = window.location.hash;
|
||||
var args = _fullArgsString.replace("#", "").split("/").slice(0);
|
||||
|
||||
for(var i=0, count = args.length; i<count; i++)
|
||||
args[i] = decodeURIComponent(args[i]);
|
||||
|
||||
_args = args;
|
||||
if (_fullArgsString.length)
|
||||
{
|
||||
var args = _fullArgsString.substring(1).split("/");
|
||||
|
||||
for (var i = 0, count = args.length; i < count; i++)
|
||||
args[i] = decodeURIComponent(args[i]);
|
||||
|
||||
_args = args;
|
||||
}
|
||||
else
|
||||
_args = [];
|
||||
}
|
||||
|
||||
- (CPDictionary)namedArguments
|
||||
@@ -770,12 +990,85 @@ CPRunContinuesResponse = -1002;
|
||||
return _namedArgs;
|
||||
}
|
||||
|
||||
- (BOOL)_openFile:(CPString)aFilename
|
||||
- (BOOL)_openURL:(CPURL)aURL
|
||||
{
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(application:openFile:)])
|
||||
return [_delegate application:self openFile:aFilename];
|
||||
{
|
||||
CPLog.warn("application:openFile: is deprecated, use application:openURL: instead.");
|
||||
return [_delegate application:self openFile:[aURL absoluteString]];
|
||||
}
|
||||
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(application:openURL:)])
|
||||
return [_delegate application:self openURL:aURL];
|
||||
|
||||
return !![_documentController openDocumentWithContentsOfURL:aURL display:YES error:NULL];
|
||||
}
|
||||
|
||||
- (void)_willBecomeActive
|
||||
{
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillBecomeActiveNotification
|
||||
object:self
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
- (void)_didBecomeActive
|
||||
{
|
||||
if (![self keyWindow] && _previousKeyWindow &&
|
||||
[[self windows] indexOfObjectIdenticalTo:_previousKeyWindow] !== CPNotFound)
|
||||
[_previousKeyWindow makeKeyWindow];
|
||||
|
||||
if (![self mainWindow] && _previousMainWindow &&
|
||||
[[self windows] indexOfObjectIdenticalTo:_previousMainWindow] !== CPNotFound)
|
||||
[_previousMainWindow makeMainWindow];
|
||||
|
||||
if ([self keyWindow])
|
||||
[[self keyWindow] orderFront:self];
|
||||
else if ([self mainWindow])
|
||||
[[self mainWindow] makeKeyAndOrderFront:self];
|
||||
else
|
||||
return [_documentController openDocumentWithContentsOfURL:aFilename display:YES error:NULL];
|
||||
[[self mainMenu]._menuWindow makeKeyWindow]; //FIXME this may not actually work
|
||||
|
||||
_previousKeyWindow = nil;
|
||||
_previousMainWindow = nil;
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidBecomeActiveNotification
|
||||
object:self
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
- (void)_willResignActive
|
||||
{
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillResignActiveNotification
|
||||
object:self
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
- (void)_didResignActive
|
||||
{
|
||||
if (self._activeMenu)
|
||||
[self._activeMenu cancelTracking];
|
||||
|
||||
if ([self keyWindow])
|
||||
{
|
||||
_previousKeyWindow = [self keyWindow];
|
||||
[_previousKeyWindow resignKeyWindow];
|
||||
}
|
||||
|
||||
if ([self mainWindow])
|
||||
{
|
||||
_previousMainWindow = [self mainWindow];
|
||||
[_previousMainWindow resignMainWindow];
|
||||
}
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidResignActiveNotification
|
||||
object:self
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeName
|
||||
{
|
||||
// FIXME: don't hardcode
|
||||
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -810,6 +1103,13 @@ var _CPRunModalLoop = function(anEvent)
|
||||
|
||||
function CPApplicationMain(args, namedArgs)
|
||||
{
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
// hook to allow recorder, etc to manipulate things before starting AppKit
|
||||
if (window.parent !== window && typeof window.parent._childAppIsStarting === "function")
|
||||
window.parent._childAppIsStarting(window);
|
||||
#endif
|
||||
|
||||
var mainBundle = [CPBundle mainBundle],
|
||||
principalClass = [mainBundle principalClass];
|
||||
|
||||
@@ -818,29 +1118,8 @@ function CPApplicationMain(args, namedArgs)
|
||||
|
||||
[principalClass sharedApplication];
|
||||
|
||||
//FIXME?
|
||||
if (!args)
|
||||
{
|
||||
var args = [CPApp arguments];
|
||||
|
||||
if([args containsObject:"debug"])
|
||||
CPLogRegister(CPLogPopup);
|
||||
}
|
||||
|
||||
if (!namedArgs)
|
||||
{
|
||||
var searchParams = window.location.search.substring(1).split("&");
|
||||
namedArgs = [CPDictionary dictionary];
|
||||
|
||||
for(var i=0; i<searchParams.length; i++)
|
||||
{
|
||||
var index = searchParams[i].indexOf('=');
|
||||
if(index == -1)
|
||||
[namedArgs setObject: "" forKey:searchParams[i]];
|
||||
else
|
||||
[namedArgs setObject: searchParams[i].substring(index+1) forKey: searchParams[i].substring(0, index)];
|
||||
}
|
||||
}
|
||||
if ([args containsObject:"debug"])
|
||||
CPLogRegister(CPLogPopup);
|
||||
|
||||
CPApp._args = args;
|
||||
CPApp._namedArgs = namedArgs;
|
||||
@@ -854,7 +1133,7 @@ var _CPAppBootstrapperActions = nil;
|
||||
{
|
||||
}
|
||||
|
||||
+ (void)actions
|
||||
+ (CPArray)actions
|
||||
{
|
||||
return [@selector(bootstrapPlatform), @selector(loadDefaultTheme), @selector(loadMainCibFile)];
|
||||
}
|
||||
@@ -882,16 +1161,16 @@ var _CPAppBootstrapperActions = nil;
|
||||
|
||||
+ (BOOL)loadDefaultTheme
|
||||
{
|
||||
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:@"Aristo.blend"]];
|
||||
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName] + ".blend"]];
|
||||
|
||||
[blend loadWithDelegate:self];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (void)blendDidFinishLoading:(CPBundle)aBundle
|
||||
+ (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend
|
||||
{
|
||||
[CPTheme setDefaultTheme:[CPTheme themeNamed:@"Aristo"]];
|
||||
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
|
||||
|
||||
[self performActions];
|
||||
}
|
||||
@@ -918,4 +1197,14 @@ var _CPAppBootstrapperActions = nil;
|
||||
[self performActions];
|
||||
}
|
||||
|
||||
+ (void)cibDidFailToLoad:(CPCib)aCib
|
||||
{
|
||||
throw new Error("Could not load main cib file (Did you forget to nib2cib it?).");
|
||||
}
|
||||
|
||||
+ (void)reset
|
||||
{
|
||||
_CPAppBootstrapperActions = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
+244
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* CPBox.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Ross Boucher.
|
||||
* Copyright 2009, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPView.j"
|
||||
|
||||
// CPBorderType
|
||||
CPNoBorder = 0;
|
||||
CPLineBorder = 1;
|
||||
CPBezelBorder = 2;
|
||||
CPGrooveBorder = 3;
|
||||
|
||||
@implementation CPBox : CPView
|
||||
{
|
||||
CPBorderType _borderType;
|
||||
|
||||
CPColor _borderColor;
|
||||
CPColor _fillColor;
|
||||
|
||||
float _cornerRadius;
|
||||
float _borderWidth;
|
||||
|
||||
CPSize _contentMargin;
|
||||
CPView _contentView;
|
||||
}
|
||||
|
||||
+ (id)boxEnclosingView:(CPView)aView
|
||||
{
|
||||
var box = [[self alloc] initWithFrame:CGRectMakeZero()],
|
||||
enclosingView = [aView superview];
|
||||
|
||||
[box setFrameFromContentFrame:[aView frame]];
|
||||
|
||||
[enclosingView replaceSubview:aView with:box];
|
||||
|
||||
[box setContentView:aView];
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)frameRect
|
||||
{
|
||||
self = [super initWithFrame:frameRect];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_fillColor = [CPColor clearColor];
|
||||
_borderColor = [CPColor blackColor];
|
||||
|
||||
_borderWidth = 1.0;
|
||||
_contentMargin = CGSizeMake(0.0, 0.0);
|
||||
|
||||
_contentView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||
|
||||
[self addSubview:_contentView];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// Configuring Boxes
|
||||
|
||||
- (CPRect)borderRect
|
||||
{
|
||||
return [self bounds];
|
||||
}
|
||||
|
||||
- (CPBorderType)borderType
|
||||
{
|
||||
return _borderType;
|
||||
}
|
||||
|
||||
- (void)setBorderType:(CPBorderType)value
|
||||
{
|
||||
_borderType = value;
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (CPColor)borderColor
|
||||
{
|
||||
return _borderColor;
|
||||
}
|
||||
|
||||
- (void)setBorderColor:(CPColor)color
|
||||
{
|
||||
if ([color isEqual:_borderColor])
|
||||
return;
|
||||
|
||||
_borderColor = color;
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (float)borderWidth
|
||||
{
|
||||
return _borderWidth;
|
||||
}
|
||||
|
||||
- (void)setBorderWidth:(float)width
|
||||
{
|
||||
if (width === _borderWidth)
|
||||
return;
|
||||
|
||||
_borderWidth = width;
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (float)cornerRadius
|
||||
{
|
||||
return _cornerRadius;
|
||||
}
|
||||
|
||||
- (void)setCornerRadius:(float)radius
|
||||
{
|
||||
if (radius === _cornerRadius)
|
||||
return;
|
||||
|
||||
_cornerRadius = radius;
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (CPColor)fillColor
|
||||
{
|
||||
return _fillColor;
|
||||
}
|
||||
|
||||
- (void)setFillColor:(CPColor)color
|
||||
{
|
||||
if ([color isEqual:_fillColor])
|
||||
return;
|
||||
|
||||
_fillColor = color;
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (CPView)contentView
|
||||
{
|
||||
return _contentView;
|
||||
}
|
||||
|
||||
- (void)setContentView:(CPView)aView
|
||||
{
|
||||
if (aView === _contentView)
|
||||
return;
|
||||
|
||||
[aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)];
|
||||
[self replaceSubview:_contentView with:aView];
|
||||
|
||||
_contentView = aView;
|
||||
}
|
||||
|
||||
- (CPSize)contentViewMargins
|
||||
{
|
||||
return _contentMargin;
|
||||
}
|
||||
|
||||
- (void)setContentViewMargins:(CPSize)size
|
||||
{
|
||||
if(size.width < 0 || size.height < 0)
|
||||
[CPException raise:CPGenericException reason:@"Margins must be positive"];
|
||||
|
||||
_contentMargin = CGSizeMakeCopy(size);
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)setFrameFromContentFrame:(CPRect)aRect
|
||||
{
|
||||
[self setFrame:CGRectInset(aRect, -(_contentMargin.width + _borderWidth), -(_contentMargin.height + _borderWidth))];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)sizeToFit
|
||||
{
|
||||
var contentFrame = [_contentView frame];
|
||||
|
||||
[self setFrameSize:CGSizeMake(contentFrame.size.width + _contentMargin.width * 2,
|
||||
contentFrame.size.height + _contentMargin.height * 2)];
|
||||
|
||||
[_contentView setFrameOrigin:CGPointMake(_contentMargin.width, _contentMargin.height)];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CPRect)rect
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
aContext = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
border2 = _borderWidth/2,
|
||||
|
||||
strokeRect = CGRectMake(bounds.origin.x + border2,
|
||||
bounds.origin.y + border2,
|
||||
bounds.size.width - _borderWidth,
|
||||
bounds.size.height - _borderWidth),
|
||||
|
||||
fillRect = CGRectMake(bounds.origin.x + border2,
|
||||
bounds.origin.y + border2,
|
||||
bounds.size.width - _borderWidth,
|
||||
bounds.size.height - _borderWidth);
|
||||
|
||||
CGContextSetFillColor(aContext, [self fillColor]);
|
||||
CGContextSetStrokeColor(aContext, [self borderColor]);
|
||||
CGContextSetLineWidth(aContext, _borderWidth);
|
||||
|
||||
switch(_borderType)
|
||||
{
|
||||
case CPLineBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
|
||||
CGContextStrokeRoundedRectangleInRect(aContext, strokeRect, _cornerRadius, YES, YES, YES, YES);
|
||||
break;
|
||||
|
||||
case CPBezelBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
|
||||
CGContextSetStrokeColor(aContext, [CPColor colorWithWhite:190.0/255.0 alpha:1.0]);
|
||||
CGContextBeginPath(aContext);
|
||||
CGContextMoveToPoint(aContext, strokeRect.origin.x, strokeRect.origin.y);
|
||||
CGContextAddLineToPoint(aContext, CGRectGetMinX(strokeRect), CGRectGetMaxY(strokeRect)),
|
||||
CGContextAddLineToPoint(aContext, CGRectGetMaxX(strokeRect), CGRectGetMaxY(strokeRect)),
|
||||
CGContextAddLineToPoint(aContext, CGRectGetMaxX(strokeRect), CGRectGetMinY(strokeRect)),
|
||||
CGContextStrokePath(aContext);
|
||||
CGContextSetStrokeColor(aContext, [CPColor colorWithWhite:142.0/255.0 alpha:1.0]);
|
||||
CGContextBeginPath(aContext);
|
||||
CGContextMoveToPoint(aContext, bounds.origin.x, strokeRect.origin.y);
|
||||
CGContextAddLineToPoint(aContext, CGRectGetMaxX(bounds), CGRectGetMinY(strokeRect));
|
||||
CGContextStrokePath(aContext);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,896 @@
|
||||
/*
|
||||
* CPBrowser.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Ross Boucher.
|
||||
* Copyright 2010, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPControl.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPTableView.j"
|
||||
@import "CPScrollView.j"
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPBrowser
|
||||
*/
|
||||
|
||||
@implementation CPBrowser : CPControl
|
||||
{
|
||||
id _delegate;
|
||||
CPString _pathSeparator;
|
||||
|
||||
CPView _contentView;
|
||||
CPScrollView _horizontalScrollView;
|
||||
CPView _prototypeView;
|
||||
|
||||
CPArray _tableViews;
|
||||
CPArray _tableDelegates;
|
||||
|
||||
id _rootItem;
|
||||
|
||||
BOOL _delegateSupportsImages;
|
||||
|
||||
SEL _doubleAction @accessors(property=doubleAction);
|
||||
|
||||
BOOL _allowsMultipleSelection;
|
||||
BOOL _allowsEmptySelection;
|
||||
|
||||
Class _tableViewClass @accessors(property=tableViewClass);
|
||||
|
||||
float _rowHeight;
|
||||
float _imageWidth;
|
||||
float _leafWidth;
|
||||
float _minColumnWidth;
|
||||
float _defaultColumnWidth @accessors(property=defaultColumnWidth);
|
||||
|
||||
CPArray _columnWidths;
|
||||
}
|
||||
|
||||
+ (CPImage)branchImage
|
||||
{
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[self class]]
|
||||
pathForResource:"browser-leaf.png"]
|
||||
size:CGSizeMake(9,9)];
|
||||
}
|
||||
|
||||
+ (CPImage)highlightedBranchImage
|
||||
{
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[self class]]
|
||||
pathForResource:"browser-leaf-highlighted.png"]
|
||||
size:CGSizeMake(9,9)];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_rowHeight = 23.0;
|
||||
_defaultColumnWidth = 140.0;
|
||||
_minColumnWidth = 80.0;
|
||||
_imageWidth = 23.0;
|
||||
_leafWidth = 13.0;
|
||||
_columnWidths = [];
|
||||
|
||||
_pathSeparator = "/";
|
||||
_tableViews = [];
|
||||
_tableDelegates = [];
|
||||
_allowsMultipleSelection = YES;
|
||||
_allowsEmptySelection = YES;
|
||||
_tableViewClass = [_CPBrowserTableView class];
|
||||
|
||||
_prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
[_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||
[_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelected];
|
||||
[_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail];
|
||||
|
||||
_horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
|
||||
|
||||
[_horizontalScrollView setHasVerticalScroller:NO];
|
||||
[_horizontalScrollView setAutohidesScrollers:YES];
|
||||
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
|
||||
_contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))];
|
||||
[_contentView setAutoresizingMask:CPViewHeightSizable];
|
||||
|
||||
[_horizontalScrollView setDocumentView:_contentView];
|
||||
|
||||
[self addSubview:_horizontalScrollView];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setPrototypeView:(CPView)aPrototypeView
|
||||
{
|
||||
_prototypeView = [CPKeyedUnarchiver unarchiveObjectWithData:
|
||||
[CPKeyedArchiver archivedDataWithRootObject:aPrototypeView]];
|
||||
}
|
||||
|
||||
- (CPView)prototypeView
|
||||
{
|
||||
return [CPKeyedUnarchiver unarchiveObjectWithData:
|
||||
[CPKeyedArchiver archivedDataWithRootObject:_prototypeView]];
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)anObject
|
||||
{
|
||||
_delegate = anObject;
|
||||
_delegateSupportsImages = [_delegate respondsToSelector:@selector(browser:imageValueForItem:)];
|
||||
|
||||
[self loadColumnZero];
|
||||
}
|
||||
|
||||
- (id)delegate
|
||||
{
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
- (CPTableView)tableViewInColumn:(unsigned)index
|
||||
{
|
||||
return _tableViews[index];
|
||||
}
|
||||
|
||||
- (unsigned)columnOfTableView:(CPTableView)aTableView
|
||||
{
|
||||
return [_tableViews indexOfObject:aTableView];
|
||||
}
|
||||
|
||||
- (void)loadColumnZero
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(rootItemForBrowser:)])
|
||||
_rootItem = [_delegate rootItemForBrowser:self];
|
||||
else
|
||||
_rootItem = nil;
|
||||
|
||||
[self setLastColumn:-1];
|
||||
[self addColumn];
|
||||
}
|
||||
|
||||
- (void)setLastColumn:(int)columnIndex
|
||||
{
|
||||
if (columnIndex >= _tableViews.length)
|
||||
return;
|
||||
|
||||
var oldValue = _tableViews.length - 1;
|
||||
|
||||
// unloads all later columns.
|
||||
var indexPlusOne = columnIndex + 1;
|
||||
|
||||
[[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
|
||||
makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
|
||||
_tableViews = _tableViews.slice(0, indexPlusOne);
|
||||
_tableDelegates = _tableDelegates.slice(0, indexPlusOne);
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:didChangeLastColumn:toColumn:)])
|
||||
[_delegate browser:self didChangeLastColumn:oldValue toColumn:columnIndex];
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
- (int)lastColumn
|
||||
{
|
||||
return _tableViews.length - 1;
|
||||
}
|
||||
|
||||
- (void)addColumn
|
||||
{
|
||||
var lastIndex = [self lastColumn],
|
||||
lastColumn = _tableViews[lastIndex],
|
||||
selectionIndexes = [lastColumn selectedRowIndexes];
|
||||
|
||||
if (lastIndex >= 0 && [selectionIndexes count] > 1)
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
reason:"Can't add column, column "+lastIndex+" has invalid selection."];
|
||||
|
||||
var index = lastIndex+1,
|
||||
item = index === 0 ? _rootItem : [_tableDelegates[lastIndex] childAtIndex:[selectionIndexes firstIndex]];
|
||||
|
||||
if (index > 0 && item && [self isLeafItem:item])
|
||||
return;
|
||||
|
||||
var table = [[_tableViewClass alloc] initWithFrame:CGRectMakeZero() browser:self];
|
||||
|
||||
[table setHeaderView:nil];
|
||||
[table setCornerView:nil];
|
||||
[table setAllowsMultipleSelection:_allowsMultipleSelection];
|
||||
[table setAllowsEmptySelection:_allowsEmptySelection];
|
||||
[table registerForDraggedTypes:[self registeredDraggedTypes]];
|
||||
|
||||
[self setNextResponder:table];
|
||||
|
||||
[self _addTableColumnsToTableView:table forColumnIndex:index];
|
||||
|
||||
var delegate = [[_CPBrowserTableDelegate alloc] init];
|
||||
|
||||
[delegate _setDelegate:_delegate];
|
||||
[delegate _setBrowser:self];
|
||||
[delegate _setIndex:index];
|
||||
[delegate _setItem:item];
|
||||
|
||||
_tableViews[index] = table;
|
||||
_tableDelegates[index] = delegate;
|
||||
|
||||
[table setDelegate:delegate];
|
||||
[table setDataSource:delegate];
|
||||
[table setTarget:delegate];
|
||||
[table setAction:@selector(_tableViewClicked:)];
|
||||
[table setDoubleAction:@selector(_tableViewDoubleClicked:)];
|
||||
[table setDraggingDestinationFeedbackStyle:CPTableViewDraggingDestinationFeedbackStyleRegular];
|
||||
|
||||
var scrollView = [[_CPBrowserScrollView alloc] initWithFrame:CGRectMakeZero()];
|
||||
[scrollView _setBrowser:self];
|
||||
[scrollView setDocumentView:table];
|
||||
[scrollView setHasHorizontalScroller:NO];
|
||||
[scrollView setAutoresizingMask:CPViewHeightSizable];
|
||||
|
||||
[_contentView addSubview:scrollView];
|
||||
|
||||
[self tile];
|
||||
|
||||
[self scrollColumnToVisible:index];
|
||||
}
|
||||
|
||||
- (void)_addTableColumnsToTableView:(CPTableView)aTableView forColumnIndex:(unsigned)index
|
||||
{
|
||||
if (_delegateSupportsImages)
|
||||
{
|
||||
var column = [[CPTableColumn alloc] initWithIdentifier:@"Image"],
|
||||
view = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[view setImageScaling:CPScaleProportionally];
|
||||
|
||||
[column setDataView:view];
|
||||
[column setResizingMask:CPTableColumnNoResizing];
|
||||
|
||||
[aTableView addTableColumn:column];
|
||||
}
|
||||
|
||||
var column = [[CPTableColumn alloc] initWithIdentifier:@"Content"];
|
||||
|
||||
[column setDataView:_prototypeView];
|
||||
[column setResizingMask:CPTableColumnNoResizing];
|
||||
|
||||
[aTableView addTableColumn:column];
|
||||
|
||||
var column = [[CPTableColumn alloc] initWithIdentifier:@"Leaf"],
|
||||
view = [[_CPBrowserLeafView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[view setBranchImage:[[self class] branchImage]];
|
||||
[view setHighlightedBranchImage:[[self class] highlightedBranchImage]];
|
||||
|
||||
[column setDataView:view];
|
||||
[column setResizingMask:CPTableColumnNoResizing];
|
||||
|
||||
[aTableView addTableColumn:column];
|
||||
}
|
||||
|
||||
- (void)reloadColumn:(int)column
|
||||
{
|
||||
[[self tableViewInColumn:column] reloadData];
|
||||
}
|
||||
|
||||
- (void)tile
|
||||
{
|
||||
var xOrigin = 0,
|
||||
scrollerWidth = [CPScroller scrollerWidth],
|
||||
height = CGRectGetHeight([_contentView bounds]);
|
||||
|
||||
for (var i = 0, count = _tableViews.length; i < count; i++)
|
||||
{
|
||||
var tableView = _tableViews[i],
|
||||
scrollView = [tableView enclosingScrollView],
|
||||
width = [self widthOfColumn:i],
|
||||
tableHeight = CGRectGetHeight([tableView bounds]);
|
||||
|
||||
[[tableView tableColumnWithIdentifier:"Image"] setWidth:_imageWidth];
|
||||
[[tableView tableColumnWithIdentifier:"Content"] setWidth:width - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - scrollerWidth - scrollerWidth];
|
||||
[[tableView tableColumnWithIdentifier:"Leaf"] setWidth:_leafWidth];
|
||||
|
||||
[tableView setRowHeight:_rowHeight];
|
||||
[tableView setFrameSize:CGSizeMake(width - scrollerWidth, tableHeight)];
|
||||
[scrollView setFrameOrigin:CGPointMake(xOrigin, 0)];
|
||||
[scrollView setFrameSize:CGSizeMake(width, height)];
|
||||
|
||||
xOrigin += width;
|
||||
}
|
||||
|
||||
[_contentView setFrameSize:CGSizeMake(xOrigin, height)];
|
||||
}
|
||||
|
||||
// ITEMS
|
||||
|
||||
- (id)itemAtRow:(int)row inColumn:(int)column
|
||||
{
|
||||
return [_tableDelegates[column] childAtIndex:row];
|
||||
}
|
||||
|
||||
- (BOOL)isLeafItem:(id)item
|
||||
{
|
||||
return [_delegate respondsToSelector:@selector(browser:isLeafItem:)] && [_delegate browser:self isLeafItem:item];
|
||||
}
|
||||
|
||||
- (id)parentForItemsInColumn:(int)column
|
||||
{
|
||||
return [_tableDelegates[column] _item];
|
||||
}
|
||||
|
||||
- (CPSet)selectedItems
|
||||
{
|
||||
var selectedColumn = [self selectedColumn],
|
||||
selectedIndexes = [self selectedRowIndexesInColumn:selectedColumn],
|
||||
set = [CPSet set],
|
||||
index = [selectedIndexes firstIndex];
|
||||
|
||||
while (index !== CPNotFound)
|
||||
{
|
||||
[set addObject:[self itemAtRow:index inColumn:selectedColumn]];
|
||||
index = [selectedIndexes indexGreaterThanIndex:index];
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
- (id)selectedItem
|
||||
{
|
||||
var selectedColumn = [self selectedColumn],
|
||||
selectedRow = [self selectedRowInColumn:selectedColumn];
|
||||
|
||||
return [self itemAtRow:selectedRow inColumn:selectedColumn];
|
||||
}
|
||||
|
||||
// CLICK EVENTS
|
||||
|
||||
- (void)_column:(unsigned)columnIndex clickedRow:(unsigned)rowIndex
|
||||
{
|
||||
[self setLastColumn:columnIndex];
|
||||
|
||||
if (rowIndex >= 0)
|
||||
[self addColumn];
|
||||
|
||||
[self doClick:self];
|
||||
}
|
||||
|
||||
- (void)sendAction
|
||||
{
|
||||
[self sendAction:_action to:_target];
|
||||
}
|
||||
|
||||
- (void)doClick:(id)sender
|
||||
{
|
||||
[self sendAction:_action to:_target];
|
||||
}
|
||||
|
||||
- (void)doDoubleClick:(id)sender
|
||||
{
|
||||
[self sendAction:_doubleAction to:_target];
|
||||
}
|
||||
|
||||
// SIZING
|
||||
|
||||
- (float)columnContentWidthForColumnWidth:(float)aWidth
|
||||
{
|
||||
return aWidth - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - [CPScroller scrollerWidth];
|
||||
}
|
||||
|
||||
- (float)columnWidthForColumnContentWidth:(float)aWidth
|
||||
{
|
||||
return aWidth + (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) + [CPScroller scrollerWidth];
|
||||
}
|
||||
|
||||
- (void)setImageWidth:(float)aWidth
|
||||
{
|
||||
_imageWidth = aWidth;
|
||||
[self tile];
|
||||
}
|
||||
|
||||
- (float)imageWidth
|
||||
{
|
||||
return _imageWidth;
|
||||
}
|
||||
|
||||
- (void)setMinColumnWidth:(float)minWidth
|
||||
{
|
||||
_minColumnWidth = minWidth;
|
||||
[self tile];
|
||||
}
|
||||
|
||||
- (float)minColumnWidth
|
||||
{
|
||||
return _minColumnWidth;
|
||||
}
|
||||
|
||||
- (void)setWidth:(float)aWidth ofColumn:(unsigned)column
|
||||
{
|
||||
_columnWidths[column] = aWidth;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:didResizeColumn:)])
|
||||
[_delegate browser:self didResizeColumn:column];
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
- (float)widthOfColumn:(unsigned)column
|
||||
{
|
||||
var width = _columnWidths[column];
|
||||
|
||||
if (width == null)
|
||||
width = _defaultColumnWidth;
|
||||
|
||||
return MAX([CPScroller scrollerWidth], MAX(_minColumnWidth, width));
|
||||
}
|
||||
|
||||
- (void)setRowHeight:(float)aHeight
|
||||
{
|
||||
_rowHeight = aHeight;
|
||||
}
|
||||
|
||||
- (float)rowHeight
|
||||
{
|
||||
return _rowHeight;
|
||||
}
|
||||
|
||||
// SCROLLERS
|
||||
|
||||
- (void)scrollColumnToVisible:(unsigned)columnIndex
|
||||
{
|
||||
[_contentView scrollRectToVisible:[[[self tableViewInColumn:columnIndex] enclosingScrollView] frame]];
|
||||
}
|
||||
|
||||
– (void)scrollRowToVisible:(unsigned)rowIndex inColumn:(unsigned)columnIndex
|
||||
{
|
||||
[self scrollColumnToVisible:columnIndex];
|
||||
[[self tableViewInColumn:columnIndex] scrollRowToVisible:rowIndex];
|
||||
}
|
||||
|
||||
- (BOOL)autohidesScroller
|
||||
{
|
||||
return [_horizontalScrollView autohidesScrollers];
|
||||
}
|
||||
|
||||
- (void)setAutohidesScroller:(BOOL)shouldHide
|
||||
{
|
||||
[_horizontalScrollView setAutohidesScrollers:shouldHide];
|
||||
}
|
||||
|
||||
// SELECTION
|
||||
|
||||
- (unsigned)selectedRowInColumn:(unsigned)columnIndex
|
||||
{
|
||||
if (columnIndex > [self lastColumn] || columnIndex < 0)
|
||||
return -1;
|
||||
|
||||
return [_tableViews[columnIndex] selectedRow];
|
||||
}
|
||||
|
||||
- (unsigned)selectedColumn
|
||||
{
|
||||
var column = [self lastColumn],
|
||||
row = [self selectedRowInColumn:column];
|
||||
|
||||
if (row >= 0)
|
||||
return column;
|
||||
else
|
||||
return column - 1;
|
||||
}
|
||||
|
||||
- (void)selectRow:(unsigned)row inColumn:(unsigned)column
|
||||
{
|
||||
var selectedIndexes = row === -1 ? [CPIndexSet indexSet] : [CPIndexSet indexSetWithIndex:row];
|
||||
[self selectRowIndexes:selectedIndexes inColumn:column];
|
||||
}
|
||||
|
||||
- (BOOL)allowsMultipleSelection
|
||||
{
|
||||
return _allowsMultipleSelection;
|
||||
}
|
||||
|
||||
- (void)setAllowsMultipleSelection:(BOOL)shouldAllow
|
||||
{
|
||||
if (_allowsMultipleSelection === shouldAllow)
|
||||
return;
|
||||
|
||||
_allowsMultipleSelection = shouldAllow;
|
||||
[_tableViews makeObjectsPerformSelector:@selector(setAllowsMultipleSelection:) withObject:shouldAllow];
|
||||
}
|
||||
|
||||
- (BOOL)allowsEmptySelection
|
||||
{
|
||||
return _allowsEmptySelection;
|
||||
}
|
||||
|
||||
- (void)setAllowsEmptySelection:(BOOL)shouldAllow
|
||||
{
|
||||
if (_allowsEmptySelection === shouldAllow)
|
||||
return;
|
||||
|
||||
_allowsEmptySelection = shouldAllow;
|
||||
[_tableViews makeObjectsPerformSelector:@selector(setAllowsEmptySelection:) withObject:shouldAllow];
|
||||
}
|
||||
|
||||
- (CPIndexSet)selectedRowIndexesInColumn:(unsigned)column
|
||||
{
|
||||
return [[self tableViewInColumn:column] selectedRowIndexes];
|
||||
}
|
||||
|
||||
- (void)selectRowIndexes:(CPIndexSet)indexSet inColumn:(unsigned)column
|
||||
{
|
||||
if (column < 0 || column > [self lastColumn] + 1)
|
||||
return;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:selectionIndexesForProposedSelection:inColumn:)])
|
||||
indexSet = [_delegate browser:self selectionIndexesForProposedSelection:indexSet inColumn:column];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:shouldSelectRowIndexes:inColumn:)] &&
|
||||
![_delegate browser:self shouldSelectRowIndexes:indexSet inColumn:column])
|
||||
return;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browserSelectionIsChanging:)])
|
||||
[_delegate browserSelectionIsChanging:self];
|
||||
|
||||
if (column > [self lastColumn])
|
||||
[self addColumn];
|
||||
|
||||
[self setLastColumn:column];
|
||||
|
||||
[[self tableViewInColumn:column] selectRowIndexes:indexSet byExtendingSelection:NO];
|
||||
|
||||
[self setNextResponder:[self tableViewInColumn:[self lastColumn]]];
|
||||
|
||||
[self scrollColumnToVisible:column];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browserSelectionDidChange:)])
|
||||
[_delegate browserSelectionDidChange:self];
|
||||
}
|
||||
|
||||
- (void)setBackgroundColor:(CPColor)aColor
|
||||
{
|
||||
[super setBackgroundColor:aColor];
|
||||
[_contentView setBackgroundColor:aColor];
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstResponder
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
// DRAG AND DROP
|
||||
|
||||
- (void)registerForDraggedTypes:(CPArray)types
|
||||
{
|
||||
[super registerForDraggedTypes:types];
|
||||
[_tableViews makeObjectsPerformSelector:@selector(registerForDraggedTypes:) withObject:types];
|
||||
}
|
||||
|
||||
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)columnIndex withEvent:(CPEvent)dragEvent
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:canDragRowsWithIndexes:inColumn:withEvent:)])
|
||||
return [_delegate browser:self canDragRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CPImage)draggingImageForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:draggingImageForRowsWithIndexes:inColumn:withEvent:offset:)])
|
||||
return [_delegate browser:self draggingImageForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CPView)draggingViewForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:draggingViewForRowsWithIndexes:inColumn:withEvent:offset:)])
|
||||
return [_delegate browser:self draggingViewForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPBrowserResizeControl : CPView
|
||||
{
|
||||
CGPoint _mouseDownX;
|
||||
CPBrowser _browser;
|
||||
unsigned _index;
|
||||
unsigned _width;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
_mouseDownX = [anEvent locationInWindow].x;
|
||||
_browser = [[self superview] _browser];
|
||||
_index = [_browser columnOfTableView:[[self superview] documentView]];
|
||||
_width = [_browser widthOfColumn:_index];
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(CPEvent)anEvent
|
||||
{
|
||||
var deltaX = [anEvent locationInWindow].x - _mouseDownX;
|
||||
[_browser setWidth:_width + deltaX ofColumn:_index];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var _CPBrowserResizeControlBackgroundImage = nil;
|
||||
|
||||
@implementation _CPBrowserScrollView : CPScrollView
|
||||
{
|
||||
_CPBrowserResizeControl _resizeControl;
|
||||
CPBrowser _browser @accessors;
|
||||
}
|
||||
|
||||
+ (CPImage)backgroundImage
|
||||
{
|
||||
if (!_CPBrowserResizeControlBackgroundImage)
|
||||
{
|
||||
var path = [[CPBundle bundleForClass:[self class]] pathForResource:"browser-resize-control.png"];
|
||||
_CPBrowserResizeControlBackgroundImage = [[CPImage alloc] initWithContentsOfFile:path
|
||||
size:CGSizeMake(15, 14)];
|
||||
}
|
||||
|
||||
return _CPBrowserResizeControlBackgroundImage;
|
||||
}
|
||||
|
||||
- (void)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_resizeControl = [[_CPBrowserResizeControl alloc] initWithFrame:CGRectMakeZero()];
|
||||
[_resizeControl setBackgroundColor:[CPColor colorWithPatternImage:[[self class] backgroundImage]]];
|
||||
[self addSubview:_resizeControl];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)reflectScrolledClipView:(CPClipView)aClipView
|
||||
{
|
||||
[super reflectScrolledClipView:aClipView];
|
||||
|
||||
var frame = [_verticalScroller frame];
|
||||
frame.size.height = CGRectGetHeight([self bounds]) - 14.0 - frame.origin.y;
|
||||
[_verticalScroller setFrameSize:frame.size];
|
||||
|
||||
var resizeFrame = CGRectMake(CGRectGetMinX(frame), CGRectGetMaxY(frame), [CPScroller scrollerWidth], 14.0);
|
||||
[_resizeControl setFrame:resizeFrame];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPBrowserTableView : CPTableView
|
||||
{
|
||||
CPBrowser _browser;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame browser:(CPBrowser)aBrowser
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
_browser = aBrowser;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstResponder
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
[super mouseDown:anEvent];
|
||||
[[self window] makeFirstResponder:_browser];
|
||||
}
|
||||
|
||||
- (CPView)browserView
|
||||
{
|
||||
return _browser;
|
||||
}
|
||||
|
||||
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes atPoint:(CGPoint)mouseDownPoint
|
||||
{
|
||||
return [_browser canDragRowsWithIndexes:rowIndexes inColumn:[_browser columnOfTableView:self] withEvent:[CPApp currentEvent]];
|
||||
}
|
||||
|
||||
- (CPImage)dragImageForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CPPointPointer)dragImageOffset
|
||||
{
|
||||
return [_browser draggingImageForRowsWithIndexes:dragRows inColumn:[_browser columnOfTableView:self] withEvent:dragEvent offset:dragImageOffset] ||
|
||||
[super dragImageForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragImageOffset];
|
||||
}
|
||||
|
||||
- (CPView)dragViewForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CPPoint)dragViewOffset
|
||||
{
|
||||
var count = theTableColumns.length;
|
||||
while (count--)
|
||||
{
|
||||
if ([theTableColumns[count] identifier] === "Leaf")
|
||||
[theTableColumns removeObject:theTableColumns[count]];
|
||||
}
|
||||
|
||||
return [_browser draggingViewForRowsWithIndexes:dragRows inColumn:[_browser columnOfTableView:self] withEvent:dragEvent offset:dragViewOffset] ||
|
||||
[super dragViewForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragViewOffset];
|
||||
}
|
||||
|
||||
- (void)moveUp:(id)sender
|
||||
{
|
||||
[super moveUp:sender];
|
||||
[_browser selectRow:[self selectedRow] inColumn:[_browser selectedColumn]];
|
||||
}
|
||||
|
||||
- (void)moveDown:(id)sender
|
||||
{
|
||||
[super moveDown:sender];
|
||||
[_browser selectRow:[self selectedRow] inColumn:[_browser selectedColumn]];
|
||||
}
|
||||
|
||||
- (void)moveLeft:(id)sender
|
||||
{
|
||||
var previousColumn = [_browser selectedColumn] - 1,
|
||||
selectedRow = [_browser selectedRowInColumn:previousColumn];
|
||||
|
||||
[_browser selectRow:selectedRow inColumn:previousColumn];
|
||||
}
|
||||
|
||||
- (void)moveRight:(id)sender
|
||||
{
|
||||
[_browser selectRow:0 inColumn:[_browser selectedColumn] + 1];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPBrowserTableDelegate : CPObject
|
||||
{
|
||||
CPBrowser _browser @accessors;
|
||||
unsigned _index @accessors;
|
||||
id _delegate @accessors;
|
||||
id _item @accessors;
|
||||
}
|
||||
|
||||
- (unsigned)numberOfRowsInTableView:(CPTableView)aTableView
|
||||
{
|
||||
return [_delegate browser:_browser numberOfChildrenOfItem:_item];
|
||||
}
|
||||
|
||||
- (void)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)column row:(unsigned)row
|
||||
{
|
||||
if ([column identifier] === "Image")
|
||||
return [_delegate browser:_browser imageValueForItem:[self childAtIndex:row]];
|
||||
else if ([column identifier] === "Leaf")
|
||||
return ![_browser isLeafItem:[self childAtIndex:row]];
|
||||
else
|
||||
return [_delegate browser:_browser objectValueForItem:[self childAtIndex:row]];
|
||||
}
|
||||
|
||||
- (void)_tableViewDoubleClicked:(CPTableView)aTableView
|
||||
{
|
||||
[_browser doDoubleClick:self];
|
||||
}
|
||||
|
||||
- (void)_tableViewClicked:(CPTableView)aTableView
|
||||
{
|
||||
var selectedIndexes = [aTableView selectedRowIndexes];
|
||||
[_browser _column:_index clickedRow:[selectedIndexes count] === 1 ? [selectedIndexes firstIndex] : -1];
|
||||
}
|
||||
|
||||
- (id)childAtIndex:(unsigned)index
|
||||
{
|
||||
return [_delegate browser:_browser child:index ofItem:_item];
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id)info row:(int)row dropOperation:(CPTableViewDropOperation)operation
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:acceptDrop:atRow:column:dropOperation:)])
|
||||
return [_delegate browser:_browser acceptDrop:info atRow:row column:_index dropOperation:operation];
|
||||
else
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(int)row proposedDropOperation:(CPTableViewDropOperation)operation
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:validateDrop:proposedRow:column:dropOperation:)])
|
||||
[_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
|
||||
else
|
||||
return CPDragOperationNone;
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView writeRowsWithIndexes:(CPIndexSet)rowIndexes toPasteboard:(CPPasteboard)pboard
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)])
|
||||
return [_delegate browser:_browser writeRowsWithIndexes:rowIndexes inColumn:_index toPasteboard:pboard];
|
||||
else
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)respondsToSelector:(SEL)aSelector
|
||||
{
|
||||
if (aSelector === @selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:))
|
||||
return [_delegate respondsToSelector:@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)];
|
||||
else
|
||||
return [super respondsToSelector:aSelector];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPBrowserLeafView : CPView
|
||||
{
|
||||
BOOL _isLeaf @accessors(readonly, property=isLeaf);
|
||||
CPImage _branchImage @accessors(property=branchImage);
|
||||
CPImage _highlightedBranchImage @accessors(property=highlightedBranchImage);
|
||||
}
|
||||
|
||||
- (BOOL)objectValue
|
||||
{
|
||||
return _isLeaf;
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
_isLeaf = !!aValue;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
if (aName === "image-view")
|
||||
return CGRectInset([self bounds], 1, 1);
|
||||
|
||||
return [super rectForEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
if (aName === "image-view")
|
||||
return [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
return [super createEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var imageView = [self layoutEphemeralSubviewNamed:@"image-view"
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:nil];
|
||||
|
||||
var isHighlighted = [self themeState] & CPThemeStateSelected;
|
||||
[imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil];
|
||||
[imageView setImageScaling:CPScaleNone];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeBool:_isLeaf forKey:"_CPBrowserLeafViewIsLeafKey"];
|
||||
[aCoder encodeObject:_branchImage forKey:"_CPBrowserLeafViewBranchImageKey"];
|
||||
[aCoder encodeObject:_highlightedBranchImage forKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
|
||||
}
|
||||
|
||||
- (void)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_isLeaf = [aCoder decodeBoolForKey:"_CPBrowserLeafViewIsLeafKey"];
|
||||
_branchImage = [aCoder decodeObjectForKey:"_CPBrowserLeafViewBranchImageKey"];
|
||||
_highlightedBranchImage = [aCoder decodeObjectForKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
+7
-31
@@ -24,32 +24,11 @@
|
||||
@import "CGGeometry.j"
|
||||
|
||||
@import "CPControl.j"
|
||||
@import "CPStringDrawing.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
CPScaleProportionally = 0;
|
||||
CPScaleToFit = 1;
|
||||
CPScaleNone = 2;
|
||||
|
||||
|
||||
/* @group CPCellImagePosition */
|
||||
|
||||
CPNoImage = 0;
|
||||
CPImageOnly = 1;
|
||||
CPImageLeft = 2;
|
||||
CPImageRight = 3;
|
||||
CPImageBelow = 4;
|
||||
CPImageAbove = 5;
|
||||
CPImageOverlaps = 6;
|
||||
|
||||
|
||||
/* @group CPButtonState */
|
||||
|
||||
CPOnState = 1;
|
||||
CPOffState = 0;
|
||||
CPMixedState = -1;
|
||||
|
||||
/* @group CPBezelStyle */
|
||||
|
||||
CPRoundedBezelStyle = 1;
|
||||
@@ -145,7 +124,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), nil]
|
||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
|
||||
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
|
||||
}
|
||||
|
||||
@@ -192,8 +171,8 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
|
||||
_allowsMixedState = aFlag;
|
||||
|
||||
if (!_allowsMixedState)
|
||||
[self unsetThemeState:CPButtonStateMixed];
|
||||
if (!_allowsMixedState && [self state] === CPMixedState)
|
||||
[self setState:CPOnState];
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)anObjectValue
|
||||
@@ -460,7 +439,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
return bounds;
|
||||
}
|
||||
|
||||
- (CGRect)bezelRectForBounds:(CFRect)bounds
|
||||
- (CGRect)bezelRectForBounds:(CGRect)bounds
|
||||
{
|
||||
if (![self isBordered])
|
||||
return _CGRectMakeZero();
|
||||
@@ -523,8 +502,6 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
}
|
||||
else
|
||||
return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
return [super createEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
@@ -532,9 +509,8 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:@"content-view"];
|
||||
|
||||
if (bezelView)
|
||||
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
||||
|
||||
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
||||
|
||||
var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
|
||||
positioned:CPWindowAbove
|
||||
|
||||
+213
-25
@@ -4,8 +4,33 @@
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
@implementation CPButtonBar : CPControl
|
||||
@implementation CPButtonBar : CPView
|
||||
{
|
||||
BOOL _hasResizeControl;
|
||||
BOOL _resizeControlIsLeftAligned;
|
||||
CPArray _buttons;
|
||||
}
|
||||
|
||||
+ (id)plusButton
|
||||
{
|
||||
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
||||
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:self] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)];
|
||||
|
||||
[button setImage:image];
|
||||
[button setImagePosition:CPImageOnly];
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
+ (id)minusButton
|
||||
{
|
||||
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
||||
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:self] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
|
||||
|
||||
[button setImage:image];
|
||||
[button setImagePosition:CPImageOnly];
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
@@ -15,47 +40,210 @@
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[nil]
|
||||
forKeys:[@"bezel-color"]];
|
||||
return [CPDictionary dictionaryWithObjects:[CGInsetMake(0.0, 0.0, 0.0, 0.0), CGSizeMakeZero(), [CPNull null], [CPNull null], [CPNull null]]
|
||||
forKeys:[@"resize-control-inset", @"resize-control-size", @"resize-control-color", @"bezel-color", @"button-bezel-color"]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_buttons = [];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)awakeFromCib
|
||||
{
|
||||
var view = [self superview],
|
||||
subview = self;
|
||||
|
||||
while (view)
|
||||
{
|
||||
if ([view isKindOfClass:[CPSplitView class]])
|
||||
{
|
||||
var viewIndex = [[view subviews] indexOfObject:subview];
|
||||
[view setButtonBar:self forDividerAtIndex:viewIndex];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
subview = view;
|
||||
view = [view superview];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setButtons:(CPArray)buttons
|
||||
{
|
||||
_buttons = [CPArray arrayWithArray:buttons];
|
||||
|
||||
for (var i = 0, count = [_buttons count]; i < count; i++)
|
||||
{
|
||||
var button = _buttons[i];
|
||||
|
||||
var normalColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateNormal],
|
||||
highlightedColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateHighlighted],
|
||||
disabledColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateDisabled];
|
||||
|
||||
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal|CPThemeStateBordered];
|
||||
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted|CPThemeStateBordered];
|
||||
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled|CPThemeStateBordered];
|
||||
|
||||
// FIXME shouldn't need this
|
||||
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal|CPThemeStateBordered|CPPopUpButtonStatePullsDown];
|
||||
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted|CPThemeStateBordered|CPPopUpButtonStatePullsDown];
|
||||
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled|CPThemeStateBordered|CPPopUpButtonStatePullsDown];
|
||||
|
||||
[button setBordered:YES];
|
||||
}
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (CPArray)buttons
|
||||
{
|
||||
return [CPArray arrayWithArray:_buttons];
|
||||
}
|
||||
|
||||
- (void)setHasResizeControl:(BOOL)shouldHaveResizeControl
|
||||
{
|
||||
if (_hasResizeControl === shouldHaveResizeControl)
|
||||
return;
|
||||
|
||||
_hasResizeControl = !!shouldHaveResizeControl;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (BOOL)hasResizeControl
|
||||
{
|
||||
return _hasResizeControl;
|
||||
}
|
||||
|
||||
- (void)setResizeControlIsLeftAligned:(BOOL)shouldBeLeftAligned
|
||||
{
|
||||
if (_resizeControlIsLeftAligned === shouldBeLeftAligned)
|
||||
return;
|
||||
|
||||
_resizeControlIsLeftAligned = !!shouldBeLeftAligned;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (BOOL)resizeControlIsLeftAligned
|
||||
{
|
||||
return _resizeControlIsLeftAligned;
|
||||
}
|
||||
|
||||
- (CGRect)resizeControlFrame
|
||||
{
|
||||
var inset = [self currentValueForThemeAttribute:@"resize-control-inset"],
|
||||
size = [self currentValueForThemeAttribute:@"resize-control-size"],
|
||||
currentSize = [self bounds],
|
||||
leftOrigin = _resizeControlIsLeftAligned ? 0 : currentSize.size.width - size.width - inset.right - inset.left;
|
||||
|
||||
return CGRectMake(leftOrigin, 0, size.width + inset.left + inset.right, size.height + inset.top + inset.bottom);
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
if (aName === "bezel-view")
|
||||
return [self bounds];
|
||||
|
||||
if (aName === "resize-control-view")
|
||||
{
|
||||
var inset = [self currentValueForThemeAttribute:@"resize-control-inset"],
|
||||
size = [self currentValueForThemeAttribute:@"resize-control-size"],
|
||||
currentSize = [self bounds];
|
||||
|
||||
if (_resizeControlIsLeftAligned)
|
||||
return CGRectMake(inset.left, inset.top, size.width, size.height);
|
||||
else
|
||||
return CGRectMake(currentSize.size.width - size.width - inset.right, inset.top, size.width, size.height);
|
||||
}
|
||||
|
||||
return [super rectForEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
if (aName === "bezel-view")
|
||||
{
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
if (aName === "resize-control-view")
|
||||
return [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
return [super createEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:@""];
|
||||
|
||||
if (bezelView)
|
||||
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
||||
}
|
||||
[self setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
||||
|
||||
- (void)addSubview:(CPView)aSubview
|
||||
{
|
||||
[super addSubview:aSubview];
|
||||
var buttonsNotHidden = [CPArray arrayWithArray:_buttons],
|
||||
count = [buttonsNotHidden count];
|
||||
|
||||
[aSubview setAutoresizingMask:CPViewMinXMargin];
|
||||
while (count--)
|
||||
if ([buttonsNotHidden[count] isHidden])
|
||||
[buttonsNotHidden removeObject:buttonsNotHidden[count]];
|
||||
|
||||
var currentButtonOffset = _resizeControlIsLeftAligned ? CGRectGetMaxX([self bounds]) + 1 : -1,
|
||||
height = CGRectGetHeight([self bounds]) - 1;
|
||||
|
||||
for (var i = 0, count = [buttonsNotHidden count]; i < count; i++)
|
||||
{
|
||||
var button = buttonsNotHidden[i],
|
||||
width = CGRectGetWidth([button frame]);
|
||||
|
||||
if (_resizeControlIsLeftAligned)
|
||||
{
|
||||
[button setFrame:CGRectMake(currentButtonOffset - width, 1, width, height)];
|
||||
currentButtonOffset -= width - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
[button setFrame:CGRectMake(currentButtonOffset, 1, width, height)];
|
||||
currentButtonOffset += width - 1;
|
||||
}
|
||||
|
||||
[self addSubview:button];
|
||||
}
|
||||
|
||||
if (_hasResizeControl)
|
||||
{
|
||||
var resizeControlView = [self layoutEphemeralSubviewNamed:@"resize-control-view"
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:nil];
|
||||
|
||||
[resizeControlView setAutoresizingMask: _resizeControlIsLeftAligned ? CPViewMaxXMargin : CPViewMinXMargin];
|
||||
[resizeControlView setBackgroundColor:[self currentValueForThemeAttribute:@"resize-control-color"]];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPButtonBarHasResizeControlKey = @"CPButtonBarHasResizeControlKey",
|
||||
CPButtonBarResizeControlIsLeftAlignedKey = @"CPButtonBarResizeControlIsLeftAlignedKey",
|
||||
CPButtonBarButtonsKey = @"CPButtonBarButtonsKey";
|
||||
|
||||
@implementation CPButtonBar (CPCoding)
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeBool:_hasResizeControl forKey:CPButtonBarHasResizeControlKey];
|
||||
[aCoder encodeBool:_resizeControlIsLeftAligned forKey:CPButtonBarResizeControlIsLeftAlignedKey];
|
||||
[aCoder encodeObject:_buttons forKey:CPButtonBarButtonsKey];
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_buttons = [aCoder decodeObjectForKey:CPButtonBarButtonsKey] || [];
|
||||
_hasResizeControl = [aCoder decodeBoolForKey:CPButtonBarHasResizeControlKey];
|
||||
_resizeControlIsLeftAligned = [aCoder decodeBoolForKey:CPButtonBarResizeControlIsLeftAlignedKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+14
-6
@@ -120,9 +120,13 @@
|
||||
|
||||
[super setBoundsOrigin:aPoint];
|
||||
|
||||
var superview = [self superview];
|
||||
|
||||
if([superview isKindOfClass:[CPScrollView class]])
|
||||
var superview = [self superview],
|
||||
|
||||
// This is hack to avoid having to import CPScrollView.
|
||||
// FIXME: Should CPScrollView be finding out about this on its own somehow?
|
||||
scrollViewClass = objj_getClass("CPScrollView");
|
||||
|
||||
if([superview isKindOfClass:scrollViewClass])
|
||||
[superview reflectScrolledClipView:self];
|
||||
}
|
||||
|
||||
@@ -173,9 +177,13 @@
|
||||
return;
|
||||
|
||||
// ... and we're in a scroll view of course.
|
||||
var superview = [self superview];
|
||||
|
||||
if ([superview isKindOfClass:[CPScrollView class]])
|
||||
var superview = [self superview],
|
||||
|
||||
// This is hack to avoid having to import CPScrollView.
|
||||
// FIXME: Should CPScrollView be finding out about this on its own somehow?
|
||||
scrollViewClass = objj_getClass("CPScrollView");
|
||||
|
||||
if ([superview isKindOfClass:scrollViewClass])
|
||||
[superview reflectScrolledClipView:self];
|
||||
}
|
||||
|
||||
|
||||
+141
-8
@@ -250,11 +250,11 @@
|
||||
|
||||
/*!
|
||||
Returns \c YES if the collection view is
|
||||
selected, and \c NO otherwise.
|
||||
selectable, and \c NO otherwise.
|
||||
*/
|
||||
- (BOOL)isSelected
|
||||
- (BOOL)isSelectable
|
||||
{
|
||||
return _isSelected;
|
||||
return _isSelectable;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -321,7 +321,7 @@
|
||||
*/
|
||||
- (CPIndexSet)selectionIndexes
|
||||
{
|
||||
return _selectionIndexes;
|
||||
return [_selectionIndexes copy];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
@@ -333,6 +333,8 @@
|
||||
while (count--)
|
||||
{
|
||||
[[_items[count] view] removeFromSuperview];
|
||||
[_items[count] setSelected:NO];
|
||||
|
||||
_cachedItems.push(_items[count]);
|
||||
}
|
||||
|
||||
@@ -351,7 +353,11 @@
|
||||
|
||||
[self addSubview:[_items[index] view]];
|
||||
}
|
||||
|
||||
|
||||
index = CPNotFound;
|
||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
|
||||
[_items[index] setSelected:YES];
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@@ -591,6 +597,10 @@
|
||||
if (![_selectionIndexes count])
|
||||
return;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:canDragItemsAtIndexes:withEvent:)] &&
|
||||
![_delegate collectionView:self canDragItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent])
|
||||
return;
|
||||
|
||||
// Set up the pasteboard
|
||||
var dragTypes = [_delegate collectionView:self dragTypesForItemsAtIndexes:_selectionIndexes];
|
||||
|
||||
@@ -670,11 +680,130 @@
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
- (CPCollectionViewItem)itemAtIndex:(unsigned)anIndex
|
||||
{
|
||||
return [_items objectAtIndex:anIndex];
|
||||
}
|
||||
|
||||
- (CGRect)frameForItemAtIndex:(unsigned)anIndex
|
||||
{
|
||||
return [[[self itemAtIndex:anIndex] view] frame];
|
||||
}
|
||||
|
||||
- (CGRect)frameForItemsAtIndexes:(CPIndexSet)anIndexSet
|
||||
{
|
||||
var indexArray = [],
|
||||
frame = CGRectNull;
|
||||
|
||||
[anIndexSet getIndexes:indexArray maxCount:-1 inIndexRange:nil];
|
||||
|
||||
var index = 0,
|
||||
count = [indexArray count];
|
||||
|
||||
for (; index < count; ++index)
|
||||
frame = CGRectUnion(frame, [self rectForItemAtIndex:indexArray[index]]);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPCollectionView (KeyboardInteraction)
|
||||
|
||||
- (void)_scrollToSelection
|
||||
{
|
||||
var frame = [self frameForItemsAtIndexes:[self selectionIndexes]];
|
||||
|
||||
if (!CGRectIsNull(frame))
|
||||
[self scrollRectToVisible:frame];
|
||||
}
|
||||
|
||||
- (void)moveLeft:(id)sender
|
||||
{
|
||||
var index = [[self selectionIndexes] firstIndex];
|
||||
if (index === CPNotFound)
|
||||
index = [[self items] count];
|
||||
|
||||
index = MAX(index - 1, 0);
|
||||
|
||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||
[self _scrollToSelection];
|
||||
}
|
||||
|
||||
- (void)moveRight:(id)sender
|
||||
{
|
||||
var index = MIN([[self selectionIndexes] firstIndex] + 1, [[self items] count]-1);
|
||||
|
||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||
[self _scrollToSelection];
|
||||
}
|
||||
|
||||
- (void)moveDown:(id)sender
|
||||
{
|
||||
var index = MIN([[self selectionIndexes] firstIndex] + [self numberOfColumns], [[self items] count]-1);
|
||||
|
||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||
[self _scrollToSelection];
|
||||
}
|
||||
|
||||
- (void)moveUp:(id)sender
|
||||
{
|
||||
var index = [[self selectionIndexes] firstIndex];
|
||||
if (index == CPNotFound)
|
||||
index = [[self items] count];
|
||||
|
||||
index = MAX(0, index - [self numberOfColumns]);
|
||||
|
||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||
[self _scrollToSelection];
|
||||
}
|
||||
|
||||
- (void)deleteBackward:(id)sender
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(collectionView:shouldDeleteItemsAtIndexes:)])
|
||||
{
|
||||
[[self delegate] collectionView:self shouldDeleteItemsAtIndexes:[self selectionIndexes]];
|
||||
|
||||
var index = [[self selectionIndexes] firstIndex];
|
||||
if (index > [[self content] count]-1)
|
||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count]-1]];
|
||||
|
||||
[self _scrollToSelection];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
{
|
||||
[self interpretKeyEvents:[anEvent]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPCollectionView (Deprecated)
|
||||
|
||||
- (CGRect)rectForItemAtIndex:(int)anIndex
|
||||
{
|
||||
_CPReportLenientDeprecation([self class], _cmd, @selector(frameForItemAtIndex:));
|
||||
|
||||
// Don't re-compute anything just grab the current frame
|
||||
// This allows subclasses to override tile without messing this up.
|
||||
return [self frameForItemAtIndex:anIndex];
|
||||
}
|
||||
|
||||
- (CGRect)rectForItemsAtIndexes:(CPIndexSet)anIndexSet
|
||||
{
|
||||
_CPReportLenientDeprecation([self class], _cmd, @selector(frameForItemsAtIndexes:));
|
||||
|
||||
return [self frameForItemsAtIndexes:anIndexSet];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
|
||||
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
|
||||
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
|
||||
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
|
||||
|
||||
|
||||
@@ -695,7 +824,10 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||
|
||||
_minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero();
|
||||
_maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero();
|
||||
|
||||
_verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey];
|
||||
|
||||
_isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey];
|
||||
|
||||
[self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]];
|
||||
|
||||
@@ -704,7 +836,6 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||
_selectionIndexes = [CPIndexSet indexSet];
|
||||
|
||||
_allowsEmptySelection = YES;
|
||||
_isSelectable = YES;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -716,10 +847,12 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||
|
||||
if (!CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
|
||||
[aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey];
|
||||
|
||||
|
||||
if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
|
||||
[aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
|
||||
|
||||
|
||||
[aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey];
|
||||
|
||||
[aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
|
||||
|
||||
[aCoder encodeObject:_backgroundColors forKey:CPCollectionViewBackgroundColorsKey];
|
||||
|
||||
+13
-56
@@ -437,51 +437,16 @@ var cachedBlackColor,
|
||||
if (self)
|
||||
{
|
||||
_components = components;
|
||||
|
||||
if (!CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0 && window.Base64 && window.CRC32)
|
||||
{
|
||||
var bytes = [0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x8,0x3,0x0,0x0,0x0,0x28,0xcb,0x34,0xbb,0x0,0x0,0x3,0x0,0x50,0x4c,0x54,0x45,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x17,0x89,0x99,0x55,0x0,0x0,0x0,0x1,0x74,0x52,0x4e,0x53,0x0,0x40,0xe6,0xd8,0x66,0x0,0x0,0x0,0x10,0x49,0x44,0x41,0x54,0x78,0xda,0x62,0x60,0x0,0x0,0x0,0x0,0xff,0xff,0x3,0x0,0x0,0x2,0x0,0x1,0x24,0x7f,0x24,0xf1,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82,0xff];
|
||||
var r_off = 41;
|
||||
var g_off = 42;
|
||||
var b_off = 43;
|
||||
var a_off = 821;
|
||||
var plte_crc_off = 809;
|
||||
var trns_crc_off = 822;
|
||||
var plte_type_off = 37;
|
||||
var trns_type_off = 817;
|
||||
|
||||
bytes[r_off] = Math.round(_components[0]*255);
|
||||
bytes[g_off] = Math.round(_components[1]*255);
|
||||
bytes[b_off] = Math.round(_components[2]*255);
|
||||
bytes[a_off] = Math.round(_components[3]*255);
|
||||
|
||||
// calculate new CRCs
|
||||
var new_plte_crc = integerToBytes(CRC32.getCRC(bytes, plte_type_off, 4+768), 4);
|
||||
var new_trns_crc = integerToBytes(CRC32.getCRC(bytes, trns_type_off, 4+1), 4);
|
||||
|
||||
// overwrite old CRCs with new ones
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
bytes[plte_crc_off+i] = new_plte_crc[i];
|
||||
bytes[trns_crc_off+i] = new_trns_crc[i];
|
||||
}
|
||||
|
||||
// Base64 encode, strip whitespace and build data URL
|
||||
var base64image = Base64.encode(bytes); //.replace(/[\s]/g, "");
|
||||
|
||||
_cssString = "url(\"data:image/png;base64," + base64image + "\")";
|
||||
}
|
||||
else
|
||||
{
|
||||
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
|
||||
|
||||
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
|
||||
parseInt(_components[0] * 255.0) + ", " +
|
||||
parseInt(_components[1] * 255.0) + ", " +
|
||||
parseInt(_components[2] * 255.0) +
|
||||
(hasAlpha ? (", " + _components[3]) : "") + ")";
|
||||
}
|
||||
|
||||
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
|
||||
|
||||
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
|
||||
parseInt(_components[0] * 255.0) + ", " +
|
||||
parseInt(_components[1] * 255.0) + ", " +
|
||||
parseInt(_components[2] * 255.0) +
|
||||
(hasAlpha ? (", " + _components[3]) : "") + ")";
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -494,6 +459,7 @@ var cachedBlackColor,
|
||||
{
|
||||
_patternImage = anImage;
|
||||
_cssString = "url(\"" + [_patternImage filename] + "\")";
|
||||
_components = [0.0, 0.0, 0.0, 1.0];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -735,6 +701,9 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
|
||||
var hexCharacters = "0123456789ABCDEF";
|
||||
|
||||
// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior
|
||||
var hexToRGB, rgbToHex, byteToHex;
|
||||
|
||||
/*!
|
||||
Used for the CPColor \c +colorWithHexString: implementation
|
||||
@ignore
|
||||
@@ -761,18 +730,6 @@ function hexToRGB(hex)
|
||||
return [red, green, blue, 1.0];
|
||||
}
|
||||
|
||||
function integerToBytes(integer, length) {
|
||||
if (!length)
|
||||
length = (integer == 0) ? 1 : Math.round((Math.log(integer)/Math.log(2))/8+0.5);
|
||||
|
||||
var bytes = new Array(length);
|
||||
for (var i = length-1; i >= 0; i--) {
|
||||
bytes[i] = integer & 255;
|
||||
integer = integer >> 8
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function rgbToHex(r,g,b) {
|
||||
return byteToHex(r) + byteToHex(g) + byteToHex(b);
|
||||
}
|
||||
|
||||
+10
-9
@@ -140,7 +140,7 @@ CPColorPickerViewHeight = 370;
|
||||
Sets the color of the panel, and updates the picker. Also posts a \c CPColorPanelDidChangeNotification.
|
||||
*/
|
||||
- (void)setColor:(CPColor)aColor
|
||||
{
|
||||
{
|
||||
_color = aColor;
|
||||
[_previewView setBackgroundColor: _color];
|
||||
|
||||
@@ -518,9 +518,10 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
|
||||
- (void)mouseUp:(CPEvent)anEvent
|
||||
{
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
bounds = [self bounds];
|
||||
|
||||
if(point.x > [self bounds].size.width - 1 || point.x < 1)
|
||||
if(!CGRectContainsPoint(bounds, point) || point.x > [self bounds].size.width - 1 || point.x < 1)
|
||||
return NO;
|
||||
|
||||
[_colorPanel setColor: [self colorAtIndex:FLOOR(point.x / 13)] updatePicker: YES];
|
||||
@@ -563,7 +564,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||
{
|
||||
if(aType == CPColorDragType)
|
||||
[aPasteboard setData:_dragColor forType:aType];
|
||||
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:_dragColor] forType:aType];
|
||||
}
|
||||
|
||||
- (void)performDragOperation:(id <CPDraggingInfo>)aSender
|
||||
@@ -575,7 +576,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
if(![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
|
||||
return NO;
|
||||
|
||||
[self setColor:[pasteboard dataForType:CPColorDragType] atIndex: FLOOR(location.x / 13)];
|
||||
[self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex: FLOOR(location.x / 13)];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -612,8 +613,8 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
if(![pasteboard availableTypeFromArray:[CPColorDragType]])
|
||||
return NO;
|
||||
|
||||
var color = [pasteboard dataForType:CPColorDragType];
|
||||
[_colorPanel setColor: color updatePicker: YES];
|
||||
var color = [CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]];
|
||||
[_colorPanel setColor:color updatePicker:YES];
|
||||
}
|
||||
|
||||
- (BOOL)isOpaque
|
||||
@@ -625,7 +626,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
{
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPArray arrayWithObject:CPColorDragType] owner:self];
|
||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
|
||||
|
||||
var bounds = CPRectMake(0, 0, 15, 15);
|
||||
|
||||
@@ -650,7 +651,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||
{
|
||||
if(aType == CPColorDragType)
|
||||
[aPasteboard setData:[self backgroundColor] forType:aType];
|
||||
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:[self backgroundColor]] forType:aType];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
@import "CPColorPanel.j"
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPColorPicker
|
||||
@@ -239,8 +241,10 @@
|
||||
_blackWheelImage.style.filter = "alpha(opacity=0)"
|
||||
_blackWheelImage.style.position = "absolute";
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_DOMElement.appendChild(_wheelImage);
|
||||
_DOMElement.appendChild(_blackWheelImage);
|
||||
#endif
|
||||
|
||||
[self setWheelSize:aFrame.size];
|
||||
|
||||
|
||||
+42
-14
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
@import "CPEvent.j"
|
||||
@import "CPPlatform.j"
|
||||
|
||||
// Browser Engines
|
||||
CPUnknownBrowserEngine = 0;
|
||||
@@ -30,6 +31,11 @@ CPKHTMLBrowserEngine = 3;
|
||||
CPOperaBrowserEngine = 4;
|
||||
CPWebKitBrowserEngine = 5;
|
||||
|
||||
// Operating Systems
|
||||
CPMacOperatingSystem = 0;
|
||||
CPWindowsOperatingSystem = 1;
|
||||
CPOtherOperatingSystem = 2;
|
||||
|
||||
// Features
|
||||
CPCSSRGBAFeature = 1 << 5;
|
||||
|
||||
@@ -56,8 +62,7 @@ CPOpacityRequiresFilterFeature = 1 << 24;
|
||||
|
||||
//Internet explorer does not allow dynamically changing the type of an input element
|
||||
CPInputTypeCanBeChangedFeature = 1 << 25;
|
||||
|
||||
|
||||
CPHTML5DragAndDropSourceYOffBy1 = 1 << 26;
|
||||
|
||||
|
||||
var USER_AGENT = "",
|
||||
@@ -68,7 +73,7 @@ var USER_AGENT = "",
|
||||
|
||||
PLATFORM_FEATURES |= CPInputTypeCanBeChangedFeature;
|
||||
|
||||
if (typeof window != "undfined" && typeof window.navigator != "undefined")
|
||||
if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
|
||||
USER_AGENT = window.navigator.userAgent;
|
||||
|
||||
// Opera
|
||||
@@ -102,7 +107,10 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
||||
// Features we can only be sure of with WebKit (no known independent tests)
|
||||
PLATFORM_FEATURES |= CPCSSRGBAFeature;
|
||||
PLATFORM_FEATURES |= CPHTMLContentEditableFeature;
|
||||
PLATFORM_FEATURES |= CPHTMLDragAndDropFeature;
|
||||
|
||||
if (USER_AGENT.indexOf("Chrome") === -1)
|
||||
PLATFORM_FEATURES |= CPHTMLDragAndDropFeature;
|
||||
|
||||
PLATFORM_FEATURES |= CPJavascriptClipboardEventsFeature;
|
||||
PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature;
|
||||
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
|
||||
@@ -114,8 +122,16 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
||||
majorVersion = parseInt(versionString.substring(0, versionDivision)),
|
||||
minorVersion = parseInt(versionString.substr(versionDivision + 1));
|
||||
|
||||
if((USER_AGENT.indexOf("Safari") !== CPNotFound && (majorVersion >= 525 && minorVersion > 14)) || USER_AGENT.indexOf("Chrome") !== CPNotFound)
|
||||
if((USER_AGENT.indexOf("Safari") !== CPNotFound && (majorVersion > 525 || (majorVersion === 525 && minorVersion > 14))) || USER_AGENT.indexOf("Chrome") !== CPNotFound)
|
||||
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
|
||||
|
||||
// FIXME this is a terrible hack to get around this bug:
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=21548
|
||||
if (![CPPlatform isBrowser])
|
||||
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
|
||||
|
||||
if (majorVersion < 532 || (majorVersion === 532 && minorVersion < 6))
|
||||
PLATFORM_FEATURES |= CPHTML5DragAndDropSourceYOffBy1;
|
||||
}
|
||||
|
||||
// KHTML
|
||||
@@ -173,26 +189,38 @@ function CPFeatureIsCompatible(aFeature)
|
||||
|
||||
function CPBrowserIsEngine(anEngine)
|
||||
{
|
||||
return PLATFORM_ENGINE == anEngine;
|
||||
return PLATFORM_ENGINE === anEngine;
|
||||
}
|
||||
|
||||
if (USER_AGENT.indexOf("Mac") != -1)
|
||||
function CPBrowserIsOperatingSystem(anOperatingSystem)
|
||||
{
|
||||
return OPERATING_SYSTEM === anOperatingSystem;
|
||||
}
|
||||
|
||||
OPERATING_SYSTEM = CPOtherOperatingSystem;
|
||||
|
||||
if (USER_AGENT.indexOf("Mac") !== -1)
|
||||
{
|
||||
OPERATING_SYSTEM = CPMacOperatingSystem;
|
||||
|
||||
CPPlatformActionKeyMask = CPCommandKeyMask;
|
||||
|
||||
CPUndoKeyEquivalent = @"Z";
|
||||
|
||||
CPUndoKeyEquivalent = @"z";
|
||||
CPRedoKeyEquivalent = @"Z";
|
||||
|
||||
CPUndoKeyEquivalentModifierMask = CPCommandKeyMask;
|
||||
CPRedoKeyEquivalentModifierMask = CPCommandKeyMask | CPShiftKeyMask;
|
||||
CPRedoKeyEquivalentModifierMask = CPCommandKeyMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (USER_AGENT.indexOf("Windows") !== -1)
|
||||
OPERATING_SYSTEM = CPWindowsOperatingSystem;
|
||||
|
||||
CPPlatformActionKeyMask = CPControlKeyMask;
|
||||
|
||||
CPUndoKeyEquivalent = @"Z";
|
||||
CPRedoKeyEquivalent = @"Y";
|
||||
|
||||
|
||||
CPUndoKeyEquivalent = @"z";
|
||||
CPRedoKeyEquivalent = @"y";
|
||||
|
||||
CPUndoKeyEquivalentModifierMask = CPControlKeyMask;
|
||||
CPRedoKeyEquivalentModifierMask = CPControlKeyMask;
|
||||
}
|
||||
+59
-51
@@ -28,47 +28,42 @@
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
/*
|
||||
@global
|
||||
@group CPTextAlignment
|
||||
*/
|
||||
CPLeftTextAlignment = 0;
|
||||
/*
|
||||
@global
|
||||
@group CPTextAlignment
|
||||
*/
|
||||
CPRightTextAlignment = 1;
|
||||
/*
|
||||
@global
|
||||
@group CPTextAlignment
|
||||
*/
|
||||
CPCenterTextAlignment = 2;
|
||||
/*
|
||||
@global
|
||||
@group CPTextAlignment
|
||||
*/
|
||||
CPJustifiedTextAlignment = 3;
|
||||
/*
|
||||
@global
|
||||
@group CPTextAlignment
|
||||
*/
|
||||
CPNaturalTextAlignment = 4;
|
||||
CPLeftTextAlignment = 0;
|
||||
CPRightTextAlignment = 1;
|
||||
CPCenterTextAlignment = 2;
|
||||
CPJustifiedTextAlignment = 3;
|
||||
CPNaturalTextAlignment = 4;
|
||||
|
||||
/*
|
||||
@global
|
||||
@group CPControlSize
|
||||
*/
|
||||
CPRegularControlSize = 0;
|
||||
/*
|
||||
@global
|
||||
@group CPControlSize
|
||||
*/
|
||||
CPSmallControlSize = 1;
|
||||
/*
|
||||
@global
|
||||
@group CPControlSize
|
||||
*/
|
||||
CPMiniControlSize = 2;
|
||||
CPRegularControlSize = 0;
|
||||
CPSmallControlSize = 1;
|
||||
CPMiniControlSize = 2;
|
||||
|
||||
CPLineBreakByWordWrapping = 0;
|
||||
CPLineBreakByCharWrapping = 1;
|
||||
CPLineBreakByClipping = 2;
|
||||
CPLineBreakByTruncatingHead = 3;
|
||||
CPLineBreakByTruncatingTail = 4;
|
||||
CPLineBreakByTruncatingMiddle = 5;
|
||||
|
||||
CPTopVerticalTextAlignment = 1,
|
||||
CPCenterVerticalTextAlignment = 2,
|
||||
CPBottomVerticalTextAlignment = 3;
|
||||
|
||||
CPScaleProportionally = 0;
|
||||
CPScaleToFit = 1;
|
||||
CPScaleNone = 2;
|
||||
|
||||
CPNoImage = 0;
|
||||
CPImageOnly = 1;
|
||||
CPImageLeft = 2;
|
||||
CPImageRight = 3;
|
||||
CPImageBelow = 4;
|
||||
CPImageAbove = 5;
|
||||
CPImageOverlaps = 6;
|
||||
|
||||
CPOnState = 1;
|
||||
CPOffState = 0;
|
||||
CPMixedState = -1;
|
||||
|
||||
CPControlNormalBackgroundColor = "CPControlNormalBackgroundColor";
|
||||
CPControlSelectedBackgroundColor = "CPControlSelectedBackgroundColor";
|
||||
@@ -95,7 +90,8 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
id _target;
|
||||
SEL _action;
|
||||
int _sendActionOn;
|
||||
|
||||
BOOL _sendsActionOnEndEditing @accessors(property=sendsActionOnEndEditing);
|
||||
|
||||
// Mouse Tracking Support
|
||||
BOOL _continuousTracking;
|
||||
BOOL _trackingWasWithinFrame;
|
||||
@@ -112,7 +108,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
CPLineBreakByClipping,
|
||||
[CPColor blackColor],
|
||||
[CPFont systemFontOfSize:12.0],
|
||||
nil,
|
||||
[CPNull null],
|
||||
_CGSizeMakeZero(),
|
||||
CPImageLeft,
|
||||
CPScaleToFit,
|
||||
@@ -304,14 +300,6 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
_previousTrackingLocation = currentLocation;
|
||||
}
|
||||
|
||||
- (void)performClick:(id)sender
|
||||
{
|
||||
[self highlight:YES];
|
||||
[self setState:[self nextState]];
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
[self highlight:NO];
|
||||
}
|
||||
|
||||
- (void)setState:(int)state
|
||||
{
|
||||
}
|
||||
@@ -321,6 +309,20 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (void)performClick:(id)sender
|
||||
{
|
||||
[self highlight:YES];
|
||||
[self setState:[self nextState]];
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
|
||||
}
|
||||
|
||||
- (void)unhighlightButtonTimerDidFinish:(id)sender
|
||||
{
|
||||
[self highlight:NO];
|
||||
}
|
||||
|
||||
- (unsigned)mouseDownFlags
|
||||
{
|
||||
return _trackingMouseDownFlags;
|
||||
@@ -590,7 +592,9 @@ var CPControlValueKey = "CPControlValueKey",
|
||||
|
||||
CPControlTargetKey = "CPControlTargetKey",
|
||||
CPControlActionKey = "CPControlActionKey",
|
||||
CPControlSendActionOnKey = "CPControlSendActionOnKey";
|
||||
CPControlSendActionOnKey = "CPControlSendActionOnKey",
|
||||
|
||||
CPControlSendsActionOnEndEditingKey = "CPControlSendsActionOnEndEditingKey";
|
||||
|
||||
var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
||||
|
||||
@@ -613,6 +617,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
||||
[self setAction:[aCoder decodeObjectForKey:CPControlActionKey]];
|
||||
|
||||
[self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]];
|
||||
[self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -626,6 +631,9 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
if (_sendsActionOnEndEditing)
|
||||
[aCoder encodeBool:_sendsActionOnEndEditing forKey:CPControlSendsActionOnEndEditingKey];
|
||||
|
||||
if (_value !== nil)
|
||||
[aCoder encodeObject:_value forKey:CPControlValueKey];
|
||||
|
||||
|
||||
Executable
+272
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
Testing browsers:
|
||||
WebKit r50235 (Safari 4.0.3+)
|
||||
FireFox 3.5
|
||||
Opera 10.0.0
|
||||
|
||||
Implemented class methods:
|
||||
Webkit : All
|
||||
IE : All
|
||||
FireFox Win : All
|
||||
FireFox Mac : All except closedHandCursor disappearingItemCursor // Firefox mac does not support url cursors
|
||||
Opera : All except resizeLeftRightCursor resizeUpDownCursor operationNotAllowedCursor dragCopyCursor dragLinkCursor contextualMenuCursor openHandCursor closedHandCursor disappearingItemCursor // Opera does not support url cursors so these won't work with images
|
||||
*/
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
var currentCursor = nil,
|
||||
cursorStack = [],
|
||||
cursors = {},
|
||||
cursorURLFormat = nil;
|
||||
|
||||
@implementation CPCursor : CPObject
|
||||
{
|
||||
CPString _cssString;
|
||||
BOOL _isSetOnMouseEntered @accessors(readwrite, getter=isSetOnMouseEntered, setter=setOnMouseEntered:);
|
||||
BOOL _isSetOnMouseExited @accessors(readwrite, getter=isSetOnMouseExited, setter=setOnMouseExited:);
|
||||
}
|
||||
|
||||
+ (CPCursor)currentCursor
|
||||
{
|
||||
return currentCursor;
|
||||
}
|
||||
|
||||
- (id)initWithCSSString:(CPString)aString
|
||||
{
|
||||
if (self = [super init])
|
||||
_cssString = aString;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (CPCursor)cursorWithCSSString:(CPString)cssString
|
||||
{
|
||||
var cursor = cursors[cssString];
|
||||
|
||||
if (typeof cursor == 'undefined')
|
||||
{
|
||||
cursor = [[CPCursor alloc] initWithCSSString:cssString];
|
||||
cursors[cssString] = cursor;
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
+ (CPCursor)cursorWithImageNamed:(CPString)imageName
|
||||
{
|
||||
if (!cursorURLFormat)
|
||||
{
|
||||
cursorURLFormat = @"url(" + [[CPBundle bundleForClass:self] resourcePath] + @"/CPCursor/%@.cur)";
|
||||
|
||||
if (CPBrowserIsEngine(CPGeckoBrowserEngine))
|
||||
cursorURLFormat += ", default";
|
||||
}
|
||||
|
||||
var url = [CPString stringWithFormat:cursorURLFormat, imageName];
|
||||
|
||||
return [[CPCursor alloc] initWithCSSString:url];
|
||||
}
|
||||
|
||||
- (CPString)_cssString
|
||||
{
|
||||
return _cssString;
|
||||
}
|
||||
|
||||
+ (CPCursor)arrowCursor
|
||||
{
|
||||
return [CPCursor cursorWithCSSString:@"default"]; // WebKit | FF | opera | IE
|
||||
}
|
||||
|
||||
+ (CPCursor)crosshairCursor
|
||||
{
|
||||
return [CPCursor cursorWithCSSString:@"crosshair"]; // WebKit | FF | opera | IE
|
||||
}
|
||||
|
||||
+ (CPCursor)IBeamCursor
|
||||
{
|
||||
return [CPCursor cursorWithCSSString:@"text"]; // WebKit | FF | opera | IE
|
||||
}
|
||||
|
||||
+ (CPCursor)pointingHandCursor
|
||||
{
|
||||
return [CPCursor cursorWithCSSString:@"pointer"]; // WebKit | FF | opera | IE
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeDownCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||
|
||||
return [CPCursor cursorWithCSSString:"s-resize"]; // WebKit | FF | opera
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeUpCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||
|
||||
return [CPCursor cursorWithCSSString:@"n-resize"]; // WebKit | FF | opera
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeLeftCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||
|
||||
return [CPCursor cursorWithCSSString:@"w-resize"]; // WebKit | FF | opera
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeRightCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||
|
||||
return [CPCursor cursorWithCSSString:@"e-resize"]; // WebKit | FF | opera
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeLeftRightCursor
|
||||
{
|
||||
return [CPCursor cursorWithCSSString:@"col-resize"]; // WebKit | FF | IE
|
||||
}
|
||||
|
||||
+ (CPCursor)resizeUpDownCursor
|
||||
{
|
||||
return [CPCursor cursorWithCSSString:@"row-resize"]; // WebKit | FF | IE
|
||||
}
|
||||
|
||||
+ (CPCursor)operationNotAllowedCursor
|
||||
{
|
||||
return [CPCursor cursorWithCSSString:@"not-allowed"]; // WebKit | FF | IE
|
||||
}
|
||||
|
||||
+ (CPCursor)dragCopyCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||
|
||||
return [CPCursor cursorWithCSSString:@"copy"]; // WebKit | FF
|
||||
}
|
||||
|
||||
+ (CPCursor)dragLinkCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||
|
||||
return [CPCursor cursorWithCSSString:@"alias"]; // WebKit | FF
|
||||
}
|
||||
|
||||
+ (CPCursor)contextualMenuCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||
|
||||
return [CPCursor cursorWithCSSString:@"context-menu"]; // WebKit | FF Mac . Not impl FF Win.
|
||||
}
|
||||
|
||||
+ (CPCursor)openHandCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
||||
return [CPCursor cursorWithCSSString:@"-webkit-grab"];
|
||||
else if (CPBrowserIsEngine(CPGeckoBrowserEngine) || CPBrowserIsEngine(CPOperaBrowserEngine))
|
||||
return [CPCursor cursorWithCSSString:@"move"];
|
||||
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only. move in FFMac|Opera
|
||||
}
|
||||
|
||||
+ (CPCursor)closedHandCursor
|
||||
{
|
||||
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
||||
return [CPCursor cursorWithCSSString:@"-webkit-grabbing"];
|
||||
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only
|
||||
}
|
||||
|
||||
+ (CPCursor)disappearingItemCursor
|
||||
{
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // None
|
||||
}
|
||||
|
||||
+ (void)hide
|
||||
{
|
||||
[self _setCursorCSS:"none"]; // Not supported in IE
|
||||
}
|
||||
|
||||
+ (void)unhide
|
||||
{
|
||||
[self _setCursorCSS:[currentCursor _cssString]]
|
||||
}
|
||||
|
||||
+ (void)setHiddenUntilMouseMoves:(BOOL)flag
|
||||
{
|
||||
if (flag)
|
||||
[CPCursor hide];
|
||||
else
|
||||
[CPCursor unhide];
|
||||
}
|
||||
|
||||
- (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot
|
||||
{
|
||||
return [self initWithCSSString:"url(" + [image filename] + ")"];
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)event
|
||||
{
|
||||
}
|
||||
|
||||
- (void)mouseExited:(CPEvent)event
|
||||
{
|
||||
}
|
||||
|
||||
- (void)set
|
||||
{
|
||||
currentCursor = self;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
[[self class] _setCursorCSS:_cssString];
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
+ (void)_setCursorCSS:(CPString)aString
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
var platformWindows = [[CPPlatformWindow visiblePlatformWindows] allObjects];
|
||||
for (var i = 0, count = [platformWindows count]; i < count; i++)
|
||||
platformWindows[i]._DOMBodyElement.style.cursor = aString;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)push
|
||||
{
|
||||
currentCursor = cursorStack.push(self);
|
||||
}
|
||||
|
||||
- (void)pop
|
||||
{
|
||||
[CPCursor pop];
|
||||
}
|
||||
|
||||
+ (void)pop
|
||||
{
|
||||
if (cursorStack.length > 1)
|
||||
{
|
||||
cursorStack.pop();
|
||||
currentCursor = cursorStack[cursorStack.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)coder
|
||||
{
|
||||
if (self = [super init])
|
||||
_cssString = [coder decodeObjectForKey:@"CPCursorNameKey"];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)coder
|
||||
{
|
||||
[coder encodeObject:_cssString forKey:@"CPCursorNameKey"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+127
-22
@@ -24,6 +24,7 @@
|
||||
@import <Foundation/CPArray.j>
|
||||
|
||||
@import "CPResponder.j"
|
||||
@import "CPSavePanel.j"
|
||||
@import "CPViewController.j"
|
||||
@import "CPWindowController.j"
|
||||
|
||||
@@ -108,6 +109,8 @@ var CPDocumentUntitledCount = 0;
|
||||
|
||||
CPURLConnection _readConnection;
|
||||
CPURLRequest _writeRequest;
|
||||
|
||||
CPAlert _canCloseAlert;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -277,14 +280,19 @@ var CPDocumentUntitledCount = 0;
|
||||
else if (viewController)
|
||||
{
|
||||
var view = [viewController view],
|
||||
theWindow = [[CPWindow alloc] initWithContentRect:[view frame] styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
|
||||
viewFrame = [view frame];
|
||||
|
||||
viewFrame.origin = CGPointMake(50, 50);
|
||||
|
||||
[theWindow setSupportsMultipleDocuments:YES];
|
||||
var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
|
||||
|
||||
windowController = [[CPWindowController alloc] initWithWindow:theWindow];
|
||||
}
|
||||
}
|
||||
|
||||
if (windowController && viewController)
|
||||
[windowController setSupportsMultipleDocuments:YES];
|
||||
|
||||
if (windowController)
|
||||
[self addWindowController:windowController];
|
||||
|
||||
@@ -310,10 +318,21 @@ var CPDocumentUntitledCount = 0;
|
||||
[_windowControllers addObject:aWindowController];
|
||||
|
||||
if ([aWindowController document] !== self)
|
||||
{
|
||||
[aWindowController setNextResponder:self];
|
||||
[aWindowController setDocument:self];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Remove a controller to the document's list of controllers. This should
|
||||
be called after closing the controller's window.
|
||||
@param aWindowController the controller to remove
|
||||
*/
|
||||
- (void)removeWindowController:(CPWindowController)aWindowController
|
||||
{
|
||||
if (aWindowController)
|
||||
[_windowControllers removeObject:aWindowController];
|
||||
|
||||
if ([aWindowController document] === self)
|
||||
[aWindowController setDocument:nil];
|
||||
}
|
||||
|
||||
- (CPView)view
|
||||
@@ -416,7 +435,7 @@ var CPDocumentUntitledCount = 0;
|
||||
|
||||
// FIXME: Oh man is this every looking for trouble, we need to handle login at the Cappuccino level, with HTTP Errors.
|
||||
_readConnection = [CPURLConnection connectionWithRequest:[CPURLRequest requestWithURL:anAbsoluteURL] delegate:self];
|
||||
|
||||
|
||||
_readConnection.session = _CPReadSessionMake(aType, aDelegate, aDidReadSelector, aContextInfo);
|
||||
}
|
||||
|
||||
@@ -459,17 +478,22 @@ var CPDocumentUntitledCount = 0;
|
||||
|
||||
_writeRequest = [CPURLRequest requestWithURL:anAbsoluteURL];
|
||||
|
||||
[_writeRequest setHTTPMethod:@"POST"];
|
||||
[_writeRequest setHTTPBody:[data string]];
|
||||
|
||||
// FIXME: THIS IS WRONG! We need a way to decide
|
||||
if ([CPPlatform isBrowser])
|
||||
[_writeRequest setHTTPMethod:@"POST"];
|
||||
else
|
||||
[_writeRequest setHTTPMethod:@"PUT"];
|
||||
|
||||
[_writeRequest setHTTPBody:[data rawString]];
|
||||
|
||||
[_writeRequest setValue:@"close" forHTTPHeaderField:@"Connection"];
|
||||
|
||||
if (aSaveOperation == CPSaveOperation)
|
||||
if (aSaveOperation === CPSaveOperation)
|
||||
[_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"];
|
||||
|
||||
if (aSaveOperation != CPSaveToOperation)
|
||||
|
||||
if (aSaveOperation !== CPSaveToOperation)
|
||||
[self updateChangeCount:CPChangeCleared];
|
||||
|
||||
|
||||
// FIXME: Oh man is this every looking for trouble, we need to handle login at the Cappuccino level, with HTTP Errors.
|
||||
var connection = [CPURLConnection connectionWithRequest:_writeRequest delegate:self];
|
||||
|
||||
@@ -526,6 +550,7 @@ var CPDocumentUntitledCount = 0;
|
||||
_writeRequest = nil;
|
||||
|
||||
objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
|
||||
[self _sendDocumentSavedNotification:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -542,7 +567,7 @@ var CPDocumentUntitledCount = 0;
|
||||
// READ
|
||||
if (aConnection == _readConnection)
|
||||
{
|
||||
[self readFromData:[CPData dataWithString:aData] ofType:session.fileType error:nil];
|
||||
[self readFromData:[CPData dataWithRawString:aData] ofType:session.fileType error:nil];
|
||||
|
||||
objj_msgSend(session.delegate, session.didReadSelector, self, YES, session.contextInfo);
|
||||
}
|
||||
@@ -554,6 +579,7 @@ var CPDocumentUntitledCount = 0;
|
||||
_writeRequest = nil;
|
||||
|
||||
objj_msgSend(session.delegate, session.didSaveSelector, self, YES, session.contextInfo);
|
||||
[self _sendDocumentSavedNotification:YES];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,6 +607,7 @@ var CPDocumentUntitledCount = 0;
|
||||
alert("There was an error saving the document.");
|
||||
|
||||
objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
|
||||
[self _sendDocumentSavedNotification:NO];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -765,6 +792,11 @@ var CPDocumentUntitledCount = 0;
|
||||
@param aSender the object requesting the save
|
||||
*/
|
||||
- (void)saveDocument:(id)aSender
|
||||
{
|
||||
[self saveDocumentWithDelegate:nil didSaveSelector:nil contextInfo:nil];
|
||||
}
|
||||
|
||||
- (void)saveDocumentWithDelegate:(id)delegate didSaveSelector:(SEL)didSaveSelector contextInfo:(Object)contextInfo
|
||||
{
|
||||
if (_fileURL)
|
||||
{
|
||||
@@ -772,10 +804,10 @@ var CPDocumentUntitledCount = 0;
|
||||
postNotificationName:CPDocumentWillSaveNotification
|
||||
object:self];
|
||||
|
||||
[self saveToURL:_fileURL ofType:[self fileType] forSaveOperation:CPSaveOperation delegate:self didSaveSelector:@selector(document:didSave:contextInfo:) contextInfo:NULL];
|
||||
[self saveToURL:_fileURL ofType:[self fileType] forSaveOperation:CPSaveOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
|
||||
}
|
||||
else
|
||||
[self saveDocumentAs:self];
|
||||
[self _saveDocumentAsWithDelegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -784,22 +816,30 @@ var CPDocumentUntitledCount = 0;
|
||||
*/
|
||||
- (void)saveDocumentAs:(id)aSender
|
||||
{
|
||||
_documentName = window.prompt("Document Name:");
|
||||
[self _saveDocumentAsWithDelegate:nil didSaveSelector:nil contextInfo:nil];
|
||||
}
|
||||
|
||||
if (!_documentName)
|
||||
- (void)_saveDocumentAsWithDelegate:(id)delegate didSaveSelector:(SEL)didSaveSelector contextInfo:(Object)contextInfo
|
||||
{
|
||||
var savePanel = [CPSavePanel savePanel],
|
||||
response = [savePanel runModal];
|
||||
|
||||
if (!response)
|
||||
return;
|
||||
|
||||
|
||||
var saveURL = [savePanel URL];
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPDocumentWillSaveNotification
|
||||
object:self];
|
||||
|
||||
[self saveToURL:[self proposedFileURL] ofType:[self fileType] forSaveOperation:CPSaveAsOperation delegate:self didSaveSelector:@selector(document:didSave:contextInfo:) contextInfo:NULL];
|
||||
|
||||
[self saveToURL:saveURL ofType:[self fileType] forSaveOperation:CPSaveAsOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (void)document:(id)aDocument didSave:(BOOL)didSave contextInfo:(id)aContextInfo
|
||||
- (void)_sendDocumentSavedNotification:(BOOL)didSave
|
||||
{
|
||||
if (didSave)
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
@@ -813,6 +853,71 @@ var CPDocumentUntitledCount = 0;
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPDocument (ClosingDocuments)
|
||||
|
||||
- (void)close
|
||||
{
|
||||
[_windowControllers makeObjectsPerformSelector:@selector(removeDocumentAndCloseIfNecessary:) withObject:self];
|
||||
[[CPDocumentController sharedDocumentController] removeDocument:self];
|
||||
}
|
||||
|
||||
- (void)shouldCloseWindowController:(CPWindowController)controller delegate:(id)delegate shouldCloseSelector:(SEL)selector contextInfo:(Object)info
|
||||
{
|
||||
if ([controller shouldCloseDocument] || ([_windowControllers count] < 2 && [_windowControllers indexOfObject:controller] !== CPNotFound))
|
||||
[self canCloseDocumentWithDelegate:self shouldCloseSelector:@selector(_document:shouldClose:context:) contextInfo:{delegate:delegate, selector:selector, context:info}];
|
||||
|
||||
else if ([delegate respondsToSelector:selector])
|
||||
objj_msgSend(delegate, selector, self, YES, info);
|
||||
}
|
||||
|
||||
- (void)_document:(CPDocument)aDocument shouldClose:(BOOL)shouldClose context:(Object)context
|
||||
{
|
||||
if (aDocument === self && shouldClose)
|
||||
[self close];
|
||||
|
||||
objj_msgSend(context.delegate, context.selector, aDocument, shouldClose, context.context);
|
||||
}
|
||||
|
||||
- (void)canCloseDocumentWithDelegate:(id)aDelegate shouldCloseSelector:(SEL)aSelector contextInfo:(Object)context
|
||||
{
|
||||
if (![self isDocumentEdited])
|
||||
return [aDelegate respondsToSelector:aSelector] && objj_msgSend(aDelegate, aSelector, self, YES, context);
|
||||
|
||||
_canCloseAlert = [[CPAlert alloc] init];
|
||||
|
||||
[_canCloseAlert setDelegate:self];
|
||||
[_canCloseAlert setAlertStyle:CPWarningAlertStyle];
|
||||
[_canCloseAlert setTitle:@"Unsaved Document"];
|
||||
[_canCloseAlert setMessageText:@"Do you want to save the changes you've made to the document \"" + ([self displayName] || [self fileName]) + "\"?"];
|
||||
|
||||
[_canCloseAlert addButtonWithTitle:@"Save"];
|
||||
[_canCloseAlert addButtonWithTitle:@"Cancel"];
|
||||
[_canCloseAlert addButtonWithTitle:@"Don't Save"];
|
||||
|
||||
_canCloseAlert._context = {delegate:aDelegate, selector:aSelector, context:context};
|
||||
|
||||
[_canCloseAlert runModal];
|
||||
}
|
||||
|
||||
- (void)alertDidEnd:(CPAlert)alert returnCode:(int)returnCode
|
||||
{
|
||||
if (alert !== _canCloseAlert)
|
||||
return;
|
||||
|
||||
var delegate = alert._context.delegate,
|
||||
selector = alert._context.selector,
|
||||
context = alert._context.context;
|
||||
|
||||
if (returnCode === 0)
|
||||
[self saveDocumentWithDelegate:delegate didSaveSelector:selector contextInfo:context];
|
||||
else
|
||||
objj_msgSend(delegate, selector, self, returnCode === 2, context);
|
||||
|
||||
_canCloseAlert = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var _CPReadSessionMake = function(aType, aDelegate, aDidReadSelector, aContextInfo)
|
||||
{
|
||||
return { fileType:aType, delegate:aDelegate, didReadSelector:aDidReadSelector, contextInfo:aContextInfo };
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
@import <Foundation/CPBundle.j>
|
||||
|
||||
@import "CPDocument.j"
|
||||
@import "CPOpenPanel.j";
|
||||
|
||||
|
||||
var CPSharedDocumentController = nil;
|
||||
@@ -113,7 +114,7 @@ var CPSharedDocumentController = nil;
|
||||
[theDocument makeWindowControllers];
|
||||
[theDocument showWindows];
|
||||
}
|
||||
|
||||
|
||||
return theDocument;
|
||||
}
|
||||
|
||||
@@ -138,16 +139,21 @@ var CPSharedDocumentController = nil;
|
||||
- (CPDocument)openDocumentWithContentsOfURL:(CPURL)anAbsoluteURL display:(BOOL)shouldDisplay error:(CPError)anError
|
||||
{
|
||||
var result = [self documentForURL:anAbsoluteURL];
|
||||
|
||||
|
||||
if (!result)
|
||||
{
|
||||
var type = [self typeForContentsOfURL:anAbsoluteURL error:anError];
|
||||
|
||||
|
||||
result = [self makeDocumentWithContentsOfURL:anAbsoluteURL ofType:type delegate:self didReadSelector:@selector(document:didRead:contextInfo:) contextInfo:[CPDictionary dictionaryWithObject:shouldDisplay forKey:@"shouldDisplay"]];
|
||||
|
||||
[self addDocument:result];
|
||||
|
||||
if (result)
|
||||
[self noteNewRecentDocument:result];
|
||||
}
|
||||
else if (shouldDisplay)
|
||||
[result showWindows];
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -203,7 +209,6 @@ var CPSharedDocumentController = nil;
|
||||
if (!didRead)
|
||||
return;
|
||||
|
||||
[self addDocument:aDocument];
|
||||
[aDocument makeWindowControllers];
|
||||
|
||||
if ([aContextInfo objectForKey:@"shouldDisplay"])
|
||||
@@ -219,6 +224,20 @@ var CPSharedDocumentController = nil;
|
||||
[self openUntitledDocumentOfType:[[_documentTypes objectAtIndex:0] objectForKey:@"CPBundleTypeName"] display:YES];
|
||||
}
|
||||
|
||||
-(void)openDocument:(id)aSender
|
||||
{
|
||||
var openPanel = [CPOpenPanel openPanel];
|
||||
|
||||
[openPanel runModal];
|
||||
|
||||
var URLs = [openPanel URLs],
|
||||
index = 0,
|
||||
count = [URLs count];
|
||||
|
||||
for (; index < count; ++index)
|
||||
[self openDocumentWithContentsOfURL:[CPURL URLWithString:URLs[index]] display:YES error:nil];
|
||||
}
|
||||
|
||||
// Managing Documents
|
||||
|
||||
/*!
|
||||
@@ -258,7 +277,8 @@ var CPSharedDocumentController = nil;
|
||||
var index = 0,
|
||||
count = _documentTypes.length,
|
||||
|
||||
extension = [[anAbsoluteURL pathExtension] lowercaseString];
|
||||
extension = [[anAbsoluteURL pathExtension] lowercaseString],
|
||||
starType = nil;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
@@ -268,12 +288,17 @@ var CPSharedDocumentController = nil;
|
||||
extensionCount = extensions.length;
|
||||
|
||||
for (; extensionIndex < extensionCount; ++extensionIndex)
|
||||
if ([extensions[extensionIndex] lowercaseString] == extension)
|
||||
{
|
||||
var thisExtension = [extensions[extensionIndex] lowercaseString];
|
||||
if (thisExtension === extension)
|
||||
return [documentType objectForKey:@"CPBundleTypeName"];
|
||||
|
||||
if (thisExtension === "****")
|
||||
starType = [documentType objectForKey:@"CPBundleTypeName"];
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME?
|
||||
return [self defaultType];//nil;
|
||||
return starType || [self defaultType];
|
||||
}
|
||||
|
||||
// Managing Document Types
|
||||
@@ -308,3 +333,125 @@ var CPSharedDocumentController = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPDocumentController (Closing)
|
||||
|
||||
- (void)closeAllDocumentsWithDelegate:(id)aDelegate didCloseAllSelector:(SEL)didCloseSelector contextInfo:(Object)info
|
||||
{
|
||||
var context = {
|
||||
delegate: aDelegate,
|
||||
selector: didCloseSelector,
|
||||
context: info
|
||||
};
|
||||
|
||||
[self _closeDocumentsStartingWith:nil shouldClose:YES context:context];
|
||||
}
|
||||
|
||||
// Recursive callback method. Start it by passing in a document of nil.
|
||||
- (void)_closeDocumentsStartingWith:(CPDocument)aDocument shouldClose:(BOOL)shouldClose context:(Object)context
|
||||
{
|
||||
if (shouldClose)
|
||||
{
|
||||
[aDocument close];
|
||||
|
||||
if ([[self documents] count] > 0)
|
||||
{
|
||||
[[[self documents] lastObject] canCloseDocumentWithDelegate:self
|
||||
shouldCloseSelector:@selector(_closeDocumentsStartingWith:shouldClose:context:)
|
||||
contextInfo:context];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ([context.delegate respondsToSelector:context.selector])
|
||||
objj_msgSend(context.delegate, context.selector, self, [[self documents] count] === 0, context.context);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPDocumentController (Recents)
|
||||
|
||||
- (CPArray)recentDocumentURLs
|
||||
{
|
||||
// FIXME move this to CP land
|
||||
if (typeof window["cpRecentDocumentURLs"] === 'function')
|
||||
return window.cpRecentDocumentURLs();
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
- (void)clearRecentDocuments:(id)sender
|
||||
{
|
||||
if (typeof window["cpClearRecentDocuments"] === 'function')
|
||||
window.cpClearRecentDocuments();
|
||||
|
||||
[self _updateRecentDocumentsMenu];
|
||||
}
|
||||
|
||||
- (void)noteNewRecentDocument:(CPDocument)aDocument
|
||||
{
|
||||
[self noteNewRecentDocumentURL:[[aDocument fileURL] absoluteString]];
|
||||
}
|
||||
|
||||
- (void)noteNewRecentDocumentURL:(CPString)aURL
|
||||
{
|
||||
if (typeof window["cpNoteNewRecentDocumentPath"] === 'function')
|
||||
window.cpNoteNewRecentDocumentPath(aURL);
|
||||
|
||||
[self _updateRecentDocumentsMenu];
|
||||
}
|
||||
|
||||
- (void)_removeAllRecentDocumentsFromMenu:(CPMenu)aMenu
|
||||
{
|
||||
var items = [aMenu itemArray],
|
||||
count = [items count];
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var item = items[count];
|
||||
|
||||
if ([item action] === @selector(_openRecentDocument:))
|
||||
[aMenu removeItemAtIndex:count];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_updateRecentDocumentsMenu
|
||||
{
|
||||
var menu = [[CPApp mainMenu] _menuWithName:@"_CPRecentDocumentsMenu"],
|
||||
recentDocuments = [self recentDocumentURLs],
|
||||
menuItems = [menu itemArray],
|
||||
documentCount = [recentDocuments count],
|
||||
menuItemCount = [menuItems count];
|
||||
|
||||
[self _removeAllRecentDocumentsFromMenu:menu];
|
||||
|
||||
if (menuItemCount)
|
||||
{
|
||||
if (!documentCount)
|
||||
{
|
||||
if ([menuItems[0] isSeparatorItem])
|
||||
[menu removeItemAtIndex:0];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (![menuItems[0] isSeparatorItem])
|
||||
[menu insertItem:[CPMenuItem separatorItem] atIndex:0];
|
||||
}
|
||||
}
|
||||
|
||||
while (documentCount--)
|
||||
{
|
||||
var path = recentDocuments[documentCount],
|
||||
item = [[CPMenuItem alloc] initWithTitle:[path lastPathComponent] action:@selector(_openRecentDocument:) keyEquivalent:nil];
|
||||
|
||||
[item setTag:path];
|
||||
[menu insertItem:item atIndex:0];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_openRecentDocument:(id)sender
|
||||
{
|
||||
[self openDocumentWithContentsOfURL:[sender tag] display:YES error:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
+26
-13
@@ -127,7 +127,7 @@ var CPDragServerDraggingInfo = nil;
|
||||
@end
|
||||
|
||||
var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
CPDraggingSource_draggedImage_endAt_operation_ = 1 << 1,
|
||||
CPDraggingSource_draggedImage_endedAt_operation_ = 1 << 1,
|
||||
CPDraggingSource_draggedView_movedTo_ = 1 << 2,
|
||||
CPDraggingSource_draggedView_endedAt_operation_ = 1 << 3;
|
||||
|
||||
@@ -150,6 +150,10 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
|
||||
CGPoint _draggingLocation;
|
||||
id _draggingDestination;
|
||||
|
||||
CGPoint _startDragLocation;
|
||||
BOOL _shouldSlideBack;
|
||||
unsigned _dragOperation;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -189,6 +193,11 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)draggingDestination
|
||||
{
|
||||
return _draggingDestination;
|
||||
}
|
||||
|
||||
- (CGPoint)draggingLocation
|
||||
{
|
||||
return _draggingLocation
|
||||
@@ -251,18 +260,17 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
return dragOperation;
|
||||
}
|
||||
|
||||
- (void)draggingEndedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation
|
||||
- (void)draggingEndedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation operation:(CPDragOperation)anOperation
|
||||
{
|
||||
[_draggedView removeFromSuperview];
|
||||
|
||||
if (![CPPlatform supportsDragAndDrop])
|
||||
[_draggedWindow orderOut:self];
|
||||
|
||||
if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_endAt_operation_)
|
||||
[_draggingSource draggedImage:[_draggedView image] endedAt:aLocation operation:NO];
|
||||
|
||||
if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_endedAt_operation_)
|
||||
[_draggingSource draggedImage:[_draggedView image] endedAt:aLocation operation:anOperation];
|
||||
else if (_implementedDraggingSourceMethods & CPDraggingSource_draggedView_endedAt_operation_)
|
||||
[_draggingSource draggedView:_draggedView endedAt:aLocation operation:NO];
|
||||
[_draggingSource draggedView:_draggedView endedAt:aLocation operation:anOperation];
|
||||
|
||||
_isDragging = NO;
|
||||
}
|
||||
@@ -296,6 +304,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
_draggingPasteboard = aPasteboard || [CPPasteboard pasteboardWithName:CPDragPboard];
|
||||
_draggingSource = aSourceObject;
|
||||
_draggingDestination = nil;
|
||||
_shouldSlideBack = slideBack;
|
||||
|
||||
// The offset is based on the distance from where we want the view to be initially from where the mouse is initially
|
||||
// Hence the use of mouseDownEvent's location and view's location in global coordinates.
|
||||
@@ -310,7 +319,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
_draggingOffset = _CGSizeMake(mouseDownEventLocation.x - viewLocation.x, mouseDownEventLocation.y - viewLocation.y);
|
||||
}
|
||||
else
|
||||
_draggingOffset = _CGSizeMakerZero();
|
||||
_draggingOffset = _CGSizeMakeZero();
|
||||
|
||||
if ([CPPlatform isBrowser])
|
||||
[_draggedWindow setPlatformWindow:[aWindow platformWindow]];
|
||||
@@ -320,7 +329,8 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
var mouseLocation = [CPEvent mouseLocation];
|
||||
|
||||
// Place it where the mouse pointer is.
|
||||
[_draggedWindow setFrameOrigin:_CGPointMake(mouseLocation.x - _draggingOffset.width, mouseLocation.y - _draggingOffset.height)];
|
||||
_startDragLocation = _CGPointMake(mouseLocation.x - _draggingOffset.width, mouseLocation.y - _draggingOffset.height);
|
||||
[_draggedWindow setFrameOrigin:_startDragLocation];
|
||||
[_draggedWindow setFrameSize:[aView frame].size];
|
||||
|
||||
[[_draggedWindow contentView] addSubview:aView];
|
||||
@@ -332,8 +342,8 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
if ([_draggingSource respondsToSelector:@selector(draggedImage:movedTo:)])
|
||||
_implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_movedTo_;
|
||||
|
||||
if ([_draggingSource respondsToSelector:@selector(draggedImage:endAt:operation:)])
|
||||
_implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_endAt_operation_;
|
||||
if ([_draggingSource respondsToSelector:@selector(draggedImage:endedAt:operation:)])
|
||||
_implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_endedAt_operation_;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -385,15 +395,18 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
{
|
||||
[self performDragOperationInPlatformWindow:platformWindow];
|
||||
[self draggingEndedInPlatformWindow:platformWindow globalLocation:platformWindowLocation];
|
||||
// Make sure we do not finalize (cancel) the drag if the last drag update was disallowed
|
||||
if (_dragOperation !== CPDragOperationNone)
|
||||
[self performDragOperationInPlatformWindow:platformWindow];
|
||||
|
||||
[self draggingEndedInPlatformWindow:platformWindow globalLocation:platformWindowLocation operation:_dragOperation];
|
||||
|
||||
// Stop tracking events.
|
||||
return;
|
||||
}
|
||||
|
||||
[self draggingSourceUpdatedWithGlobalLocation:platformWindowLocation];
|
||||
[self draggingUpdatedInPlatformWindow:platformWindow location:platformWindowLocation];
|
||||
_dragOperation = [self draggingUpdatedInPlatformWindow:platformWindow location:platformWindowLocation];
|
||||
|
||||
// If we're not a mouse up, then we're going to want to grab the next event.
|
||||
[CPApp setTarget:self selector:@selector(trackDragging:)
|
||||
|
||||
+24
-86
@@ -25,110 +25,26 @@
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPLeftMouseDown = 1;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPLeftMouseUp = 2;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPRightMouseDown = 3;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPRightMouseUp = 4;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPMouseMoved = 5;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPLeftMouseDragged = 6;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPRightMouseDragged = 7;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPMouseEntered = 8;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPMouseExited = 9;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPKeyDown = 10;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPKeyUp = 11;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPFlagsChanged = 12;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPAppKitDefined = 13;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPSystemDefined = 14;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPApplicationDefined = 15;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPPeriodic = 16;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPCursorUpdate = 17;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPScrollWheel = 22;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPOtherMouseDown = 25;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPOtherMouseUp = 26;
|
||||
/*
|
||||
@global
|
||||
@group CPEventType
|
||||
*/
|
||||
CPOtherMouseDragged = 27;
|
||||
|
||||
// iPhone Event Types
|
||||
@@ -212,7 +128,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
BOOL _isARepeat;
|
||||
unsigned _keyCode;
|
||||
DOMEvent _DOMEvent;
|
||||
|
||||
|
||||
float _deltaX;
|
||||
float _deltaY;
|
||||
float _deltaZ;
|
||||
@@ -369,6 +285,17 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
return _CGPointMakeCopy(_location);
|
||||
}
|
||||
|
||||
- (CGPoint)globalLocation
|
||||
{
|
||||
var theWindow = [self window],
|
||||
location = [self locationInWindow];
|
||||
|
||||
if (theWindow)
|
||||
return [theWindow convertBaseToGlobal:location];
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns event information as a bit mask
|
||||
*/
|
||||
@@ -418,7 +345,10 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
*/
|
||||
- (int)buttonNumber
|
||||
{
|
||||
return _buttonNumber;
|
||||
if (_type === CPRightMouseDown || _type === CPRightMouseUp || _type === CPRightMouseDragged)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -515,6 +445,14 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
return _deltaZ;
|
||||
}
|
||||
|
||||
- (BOOL)_couldBeKeyEquivalent
|
||||
{
|
||||
// FIXME: More cases? Space?
|
||||
return _type === CPKeyDown &&
|
||||
_modifierFlags & (CPCommandKeyMask | CPControlKeyMask) &&
|
||||
[_characters length] > 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Generates periodic events every \c aPeriod seconds.
|
||||
@param aDelay the number of seconds before the first event
|
||||
|
||||
+28
-5
@@ -30,7 +30,7 @@
|
||||
*/
|
||||
@implementation CPFlashMovie : CPObject
|
||||
{
|
||||
CPString _fileName;
|
||||
CPString _filename;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -38,9 +38,9 @@
|
||||
@param aFilename the swf to load
|
||||
@return the initialized CPFlashMovie
|
||||
*/
|
||||
+ (id)flashMovieWithFile:(CPString)aFileName
|
||||
+ (id)flashMovieWithFile:(CPString)aFilename
|
||||
{
|
||||
return [[self alloc] initWithFile:aFileName];
|
||||
return [[self alloc] initWithFile:aFilename];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -48,14 +48,37 @@
|
||||
@param aFilename the swf to load
|
||||
@return the initialized CPFlashMovie
|
||||
*/
|
||||
- (id)initWithFile:(CPString)aFileName
|
||||
- (id)initWithFile:(CPString)aFilename
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
_fileName = aFileName;
|
||||
_filename = aFilename;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPString)filename
|
||||
{
|
||||
return _filename;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPFlashMovieFilenameKey = "CPFlashMovieFilenameKey";
|
||||
|
||||
@implementation CPFlashMovie (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
_filename = [aCoder decodeObjectForKey:CPFlashMovieFilenameKey];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_filename forKey:CPFlashMovieFilenameKey];
|
||||
}
|
||||
|
||||
@end
|
||||
+128
-36
@@ -23,6 +23,9 @@
|
||||
@import "CPFlashMovie.j"
|
||||
@import "CPView.j"
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -31,9 +34,13 @@
|
||||
{
|
||||
CPFlashMovie _flashMovie;
|
||||
|
||||
DOMElement _DOMEmbedElement;
|
||||
DOMElement _DOMMParamElement;
|
||||
CPDictionary _params;
|
||||
CPDictionary _paramElements;
|
||||
#if PLATFORM(DOM)
|
||||
DOMElement _DOMParamElement;
|
||||
DOMElement _DOMObjectElement;
|
||||
DOMElement _DOMInnerObjectElement;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -42,35 +49,32 @@
|
||||
|
||||
if (self)
|
||||
{
|
||||
_DOMObjectElement = document.createElement("object");
|
||||
_DOMObjectElement.width = "100%";
|
||||
_DOMObjectElement.height = "100%";
|
||||
_DOMObjectElement.style.top = "0px";
|
||||
_DOMObjectElement.style.left = "0px";
|
||||
|
||||
_DOMParamElement = document.createElement("param");
|
||||
_DOMParamElement.name = "movie";
|
||||
|
||||
_DOMObjectElement.appendChild(_DOMParamElement);
|
||||
|
||||
var param = document.createElement("param");
|
||||
|
||||
param.name = "wmode";
|
||||
param.value = "transparent";
|
||||
|
||||
_DOMObjectElement.appendChild(param);
|
||||
|
||||
_DOMEmbedElement = document.createElement("embed");
|
||||
|
||||
_DOMEmbedElement.type = "application/x-shockwave-flash";
|
||||
_DOMEmbedElement.setAttribute("wmode", "transparent");
|
||||
_DOMEmbedElement.width = "100%";
|
||||
_DOMEmbedElement.height = "100%";
|
||||
|
||||
// IE requires this thing to be in the _DOMElement and not the _DOMObjectElement.
|
||||
_DOMElement.appendChild(_DOMEmbedElement);
|
||||
|
||||
_DOMElement.appendChild(_DOMObjectElement);
|
||||
#if PLATFORM(DOM)
|
||||
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
{
|
||||
_DOMObjectElement = document.createElement(@"object");
|
||||
_DOMObjectElement.width = @"100%";
|
||||
_DOMObjectElement.height = @"100%";
|
||||
_DOMObjectElement.style.top = @"0px";
|
||||
_DOMObjectElement.style.left = @"0px";
|
||||
_DOMObjectElement.type = @"application/x-shockwave-flash";
|
||||
_DOMObjectElement.setAttribute(@"classid", IEFlashCLSID);
|
||||
|
||||
_DOMParamElement = document.createElement(@"param");
|
||||
_DOMParamElement.name = @"movie";
|
||||
|
||||
_DOMInnerObjectElement = document.createElement(@"object");
|
||||
_DOMInnerObjectElement.width = @"100%";
|
||||
_DOMInnerObjectElement.height = @"100%";
|
||||
|
||||
_DOMObjectElement.appendChild(_DOMParamElement);
|
||||
_DOMObjectElement.appendChild(_DOMInnerObjectElement);
|
||||
|
||||
_DOMElement.appendChild(_DOMObjectElement);
|
||||
}
|
||||
else
|
||||
[self _rebuildIEObjects];
|
||||
#endif
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -82,11 +86,15 @@
|
||||
return;
|
||||
|
||||
_flashMovie = aFlashMovie;
|
||||
|
||||
_DOMParamElement.value = aFlashMovie._fileName;
|
||||
|
||||
if (_DOMEmbedElement)
|
||||
_DOMEmbedElement.src = aFlashMovie._fileName;
|
||||
#if PLATFORM(DOM)
|
||||
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
{
|
||||
_DOMParamElement.value = [aFlashMovie filename];
|
||||
_DOMInnerObjectElement.data = [aFlashMovie filename];
|
||||
}
|
||||
else
|
||||
[self _rebuildIEObjects];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (CPFlashMovie)flashMovie
|
||||
@@ -94,6 +102,90 @@
|
||||
return _flashMovie;
|
||||
}
|
||||
|
||||
- (void)setFlashVars:(CPDictionary)aDictionary
|
||||
{
|
||||
var varString = @"",
|
||||
enumerator = [aDictionary keyEnumerator];
|
||||
|
||||
var key;
|
||||
while (key = [enumerator nextObject])
|
||||
varString = [varString stringByAppendingFormat:@"&%@=%@", key, [aDictionary objectForKey:key]];
|
||||
|
||||
if (!_params)
|
||||
_params = [CPDictionary dictionary];
|
||||
|
||||
[_params setObject:varString forKey:@"flashvars"];
|
||||
[self setParameters:_params];
|
||||
}
|
||||
|
||||
- (CPDictionary)flashVars
|
||||
{
|
||||
return [_params objectForKey:@"flashvars"];
|
||||
}
|
||||
|
||||
- (void)setParameters:(CPDictionary)aDictionary
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
if (_paramElements && !CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
{
|
||||
var elements = [_paramElements allValues],
|
||||
count = [elements count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
_DOMObjectElement.removeChild([elements objectAtIndex:i]);
|
||||
}
|
||||
#endif
|
||||
_params = aDictionary;
|
||||
#if PLATFORM(DOM)
|
||||
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
{
|
||||
_paramElements = [CPDictionary dictionary];
|
||||
|
||||
var enumerator = [_params keyEnumerator],
|
||||
key;
|
||||
|
||||
while (key = [enumerator nextObject] && _DOMObjectElement)
|
||||
{
|
||||
var param = document.createElement(@"param");
|
||||
param.name = key;
|
||||
param.value = [_params objectForKey:key];
|
||||
|
||||
_DOMObjectElement.appendChild(param);
|
||||
|
||||
[_paramElements setObject:param forKey:key];
|
||||
}
|
||||
}
|
||||
else
|
||||
[self _rebuildIEObjects];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (CPDictionary)parameters
|
||||
{
|
||||
return _params;
|
||||
}
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
- (void)_rebuildIEObjects
|
||||
{
|
||||
_DOMElement.innerHTML = @"";
|
||||
if (![_flashMovie filename])
|
||||
return;
|
||||
|
||||
var paramString = [CPString stringWithFormat:@"<param name='movie' value='%@' />", [_flashMovie filename]],
|
||||
paramEnumerator = [_params keyEnumerator],
|
||||
key;
|
||||
|
||||
while (key = [paramEnumerator nextObject])
|
||||
paramString = [paramString stringByAppendingFormat:@"<param name='%@' value='%@' />", key, [_params objectForKey:key]];
|
||||
|
||||
_DOMObjectElement = document.createElement(@"object");
|
||||
_DOMElement.appendChild(_DOMObjectElement);
|
||||
|
||||
_DOMObjectElement.outerHTML = [CPString stringWithFormat:@"<object classid=%@ width=%@ height=%@>%@</object>", IEFlashCLSID, CGRectGetWidth([self bounds]), CGRectGetHeight([self bounds]), paramString];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)mouseDragged:(CPEvent)anEvent
|
||||
{
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
+17
-4
@@ -20,10 +20,13 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
var _CPFonts = {};
|
||||
_CPFontSystemFontFace = @"Arial";
|
||||
var _CPFonts = {},
|
||||
_CPFontSystemFontFace = @"Arial, sans-serif",
|
||||
_CPWrapRegExp = new RegExp("\\s*,\\s*", "g");
|
||||
|
||||
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[(isBold ? @"bold " : @"") + ROUND(aSize) + @"px '" + aName + @"'"]
|
||||
|
||||
#define _CPCreateCSSString(aName, aSize, isBold) (isBold ? @"bold " : @"") + ROUND(aSize) + @"px " + ((aName === _CPFontSystemFontFace) ? aName : (@"\"" + aName.replace(_CPWrapRegExp, '", "') + @"\", " + _CPFontSystemFontFace))
|
||||
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[_CPCreateCSSString(aName, aSize, isBold)]
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -95,7 +98,7 @@ var _CPFonts = {};
|
||||
_size = aSize;
|
||||
_isBold = isBold;
|
||||
|
||||
_cssString = (_isBold ? @"bold " : @"") + ROUND(aSize) + @"px '" + aName + @"'";
|
||||
_cssString = _CPCreateCSSString(_name, _size, _isBold);
|
||||
|
||||
_CPFonts[_cssString] = self;
|
||||
}
|
||||
@@ -127,6 +130,16 @@ var _CPFonts = {};
|
||||
return _name;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)anObject
|
||||
{
|
||||
return [anObject isKindOfClass:[CPFont class]] && [anObject cssString] === [self cssString];
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [CPString stringWithFormat:@"%@ %@ %f pt.", [super description], [self familyName], [self size]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPFontNameKey = @"CPFontNameKey",
|
||||
|
||||
@@ -51,7 +51,7 @@ var CPSharedFontManager = nil,
|
||||
|
||||
// Changing the Default Font Conversion Classes
|
||||
/*!
|
||||
Sets the class that will be used to create the applcation's
|
||||
Sets the class that will be used to create the application's
|
||||
font manager.
|
||||
*/
|
||||
+ (void)setFontManagerFactory:(Class)aClass
|
||||
|
||||
+2
-2
@@ -234,9 +234,9 @@ function CPRectContainsPoint(aRect, aPoint)
|
||||
@param possibleInner the CGRect to test if it fits inside \c possibleOuter.
|
||||
@return BOOL \c YES if \c possibleInner fits inside \c possibleOuter.
|
||||
*/
|
||||
function CPRectContainsRect(lhsRect, rhsRect)
|
||||
function CPRectContainsRect(possibleOuter, possibleInner)
|
||||
{
|
||||
return CPRectEqualToRect(CPUnionRect(lhsRect, rhsRect), rhsRect);
|
||||
return CGRectContainsRect(possibleOuter, possibleInner);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
+95
-37
@@ -19,7 +19,7 @@
|
||||
* 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/CPBundle.j>
|
||||
@import <Foundation/CPNotificationCenter.j>
|
||||
@import <Foundation/CPObject.j>
|
||||
@@ -28,6 +28,9 @@
|
||||
|
||||
@import "CPGeometry.j"
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
|
||||
CPImageLoadStatusInitialized = 0;
|
||||
CPImageLoadStatusLoading = 1;
|
||||
CPImageLoadStatusCompleted = 2;
|
||||
@@ -38,26 +41,32 @@ CPImageLoadStatusReadError = 6;
|
||||
|
||||
CPImageDidLoadNotification = @"CPImageDidLoadNotification";
|
||||
|
||||
// Image Names
|
||||
CPImageNameColorPanel = @"CPImageNameColorPanel";
|
||||
CPImageNameColorPanelHighlighted = @"CPImageNameColorPanelHighlighted";
|
||||
|
||||
var imagesForNames = { },
|
||||
AppKitImageForNames = { };
|
||||
|
||||
AppKitImageForNames[CPImageNameColorPanel] = CGSizeMake(26.0, 29.0);
|
||||
AppKitImageForNames[CPImageNameColorPanelHighlighted] = CGSizeMake(26.0, 29.0);
|
||||
|
||||
function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
{
|
||||
if (!aBundle)
|
||||
aBundle = [CPBundle mainBundle];
|
||||
|
||||
|
||||
if (aSize)
|
||||
return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename] size:aSize];
|
||||
|
||||
|
||||
return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename]];
|
||||
}
|
||||
|
||||
@implementation CPBundle (CPImageAdditions)
|
||||
|
||||
- (CPString)pathForResource:(CPString)aFilename
|
||||
function CPAppKitImage(aFilename, aSize)
|
||||
{
|
||||
return [self resourcePath] + '/' + aFilename;
|
||||
return CPImageInBundle(aFilename, aSize, [CPBundle bundleForClass:[CPView class]]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPImage
|
||||
@@ -83,13 +92,19 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
{
|
||||
CGSize _size;
|
||||
CPString _filename;
|
||||
|
||||
CPString _name;
|
||||
|
||||
id _delegate;
|
||||
unsigned _loadStatus;
|
||||
|
||||
|
||||
Image _image;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initByReferencingFile:@"" size:CGSizeMake(-1, -1)];
|
||||
}
|
||||
|
||||
/*!
|
||||
Initializes the image, by associating it with a filename. The image
|
||||
denoted in \c aFilename is not actually loaded. It will
|
||||
@@ -98,17 +113,17 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
@param aSize the image's size
|
||||
@return the initialized image
|
||||
*/
|
||||
- (CPImage)initByReferencingFile:(CPString)aFilename size:(CGSize)aSize
|
||||
- (id)initByReferencingFile:(CPString)aFilename size:(CGSize)aSize
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_size = CPSizeCreateCopy(aSize);
|
||||
_filename = aFilename;
|
||||
_loadStatus = CPImageLoadStatusInitialized;
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -118,13 +133,13 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
@param aSize the size of the image
|
||||
@return the initialized image.
|
||||
*/
|
||||
- (CPImage)initWithContentsOfFile:(CPString)aFilename size:(CGSize)aSize
|
||||
- (id)initWithContentsOfFile:(CPString)aFilename size:(CGSize)aSize
|
||||
{
|
||||
self = [self initByReferencingFile:aFilename size:aSize];
|
||||
|
||||
|
||||
if (self)
|
||||
[self load];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -134,13 +149,13 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
@param aFilename the file name of the image
|
||||
@return the initialized image
|
||||
*/
|
||||
- (CPImage)initWithContentsOfFile:(CPString)aFilename
|
||||
- (id)initWithContentsOfFile:(CPString)aFilename
|
||||
{
|
||||
self = [self initByReferencingFile:aFilename size: CGSizeMake(-1, -1)];
|
||||
|
||||
self = [self initByReferencingFile:aFilename size:CGSizeMake(-1, -1)];
|
||||
|
||||
if (self)
|
||||
[self load];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -169,6 +184,45 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
return _size;
|
||||
}
|
||||
|
||||
+ (id)imageNamed:(CPString)aName
|
||||
{
|
||||
var image = imagesForNames[aName];
|
||||
|
||||
if (image)
|
||||
return image;
|
||||
|
||||
var imageOrSize = AppKitImageForNames[aName];
|
||||
|
||||
if (!imageOrSize.isa)
|
||||
{
|
||||
imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize);
|
||||
|
||||
[imageOrSize setName:aName];
|
||||
|
||||
AppKitImageForNames[aName] = imageOrSize;
|
||||
}
|
||||
|
||||
return imageOrSize;
|
||||
}
|
||||
|
||||
- (void)setName:(CPString)aName
|
||||
{
|
||||
if (_name === aName)
|
||||
return;
|
||||
|
||||
if (imagesForNames[aName] === self)
|
||||
imagesForNames[aName] = nil;
|
||||
|
||||
_name = aName;
|
||||
|
||||
imagesForNames[aName] = self;
|
||||
}
|
||||
|
||||
- (CPString)name
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the receiver's delegate.
|
||||
@param the delegate
|
||||
@@ -204,9 +258,10 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
{
|
||||
if (_loadStatus == CPImageLoadStatusLoading || _loadStatus == CPImageLoadStatusCompleted)
|
||||
return;
|
||||
|
||||
|
||||
_loadStatus = CPImageLoadStatusLoading;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_image = new Image();
|
||||
|
||||
var isSynchronous = YES;
|
||||
@@ -223,7 +278,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
}
|
||||
[self _derefFromImage];
|
||||
}
|
||||
|
||||
|
||||
_image.onerror = function ()
|
||||
{
|
||||
if (isSynchronous)
|
||||
@@ -235,7 +290,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
}
|
||||
[self _derefFromImage];
|
||||
}
|
||||
|
||||
|
||||
_image.onabort = function ()
|
||||
{
|
||||
if (isSynchronous)
|
||||
@@ -247,10 +302,13 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
}
|
||||
[self _derefFromImage];
|
||||
}
|
||||
|
||||
|
||||
_image.src = _filename;
|
||||
|
||||
isSynchronous = NO;
|
||||
|
||||
// onload and friends may fire after this point but BEFORE the end of the run loop,
|
||||
// crazy, I know. So don't set isSynchronous here, rather wait a bit longer.
|
||||
window.setTimeout(function() { isSynchronous = NO; }, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
- (BOOL)isThreePartImage
|
||||
@@ -283,7 +341,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPImageDidLoadNotification
|
||||
object:self];
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(imageDidLoad:)])
|
||||
[_delegate imageDidLoad:self];
|
||||
}
|
||||
@@ -292,7 +350,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
- (void)_imageDidError
|
||||
{
|
||||
_loadStatus = CPImageLoadStatusReadError;
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(imageDidError:)])
|
||||
[_delegate imageDidError:self];
|
||||
}
|
||||
@@ -301,7 +359,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
- (void)_imageDidAbort
|
||||
{
|
||||
_loadStatus = CPImageLoadStatusCancelled;
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(imageDidAbort:)])
|
||||
[_delegate imageDidAbort:self];
|
||||
}
|
||||
@@ -341,7 +399,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
- (id)initWithImageSlices:(CPArray)imageSlices isVertical:(BOOL)isVertical
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_imageSlices = imageSlices;
|
||||
@@ -386,13 +444,13 @@ var CPThreePartImageImageSlicesKey = @"CPThreePartImageImageSlicesKey",
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_imageSlices = [aCoder decodeObjectForKey:CPThreePartImageImageSlicesKey];
|
||||
_isVertical = [aCoder decodeBoolForKey:CPThreePartImageIsVerticalKey];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -413,10 +471,10 @@ var CPThreePartImageImageSlicesKey = @"CPThreePartImageImageSlicesKey",
|
||||
- (id)initWithImageSlices:(CPArray)imageSlices
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
_imageSlices = imageSlices;
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -449,10 +507,10 @@ var CPNinePartImageImageSlicesKey = @"CPNinePartImageImageSlicesKey";
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
_imageSlices = [aCoder decodeObjectForKey:CPNinePartImageImageSlicesKey];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
+8
-14
@@ -31,24 +31,10 @@
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
/*
|
||||
@global
|
||||
@group CPImageScaling
|
||||
*/
|
||||
CPScaleProportionally = 0;
|
||||
/*
|
||||
@global
|
||||
@group CPImageScaling
|
||||
*/
|
||||
CPScaleToFit = 1;
|
||||
/*
|
||||
@global
|
||||
@group CPImageScaling
|
||||
*/
|
||||
CPScaleNone = 2;
|
||||
|
||||
|
||||
var CPImageViewShadowBackgroundColor = nil;
|
||||
|
||||
var LEFT_SHADOW_INSET = 3.0,
|
||||
@@ -225,6 +211,11 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (unsigned)imageScaling
|
||||
{
|
||||
return [self currentValueForThemeAttribute:@"image-scaling"];
|
||||
}
|
||||
|
||||
/*!
|
||||
Toggles the display of the image view.
|
||||
*/
|
||||
@@ -379,7 +370,10 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
var images = [CPKeyedUnarchiver unarchiveObjectWithData:[[aSender draggingPasteboard] dataForType:CPImagesPboardType]];
|
||||
|
||||
if ([images count])
|
||||
{
|
||||
[self setImage:images[0]];
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
-1977
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,556 @@
|
||||
|
||||
#include "../CoreGraphics/CGGeometry.h"
|
||||
#include "../Platform/Platform.h"
|
||||
|
||||
@import "_CPMenuWindow.j"
|
||||
|
||||
|
||||
var MENUBAR_HEIGHT = 28.0,
|
||||
MENUBAR_MARGIN = 10.0,
|
||||
MENUBAR_LEFT_MARGIN = 10.0,
|
||||
MENUBAR_RIGHT_MARGIN = 10.0;
|
||||
|
||||
var _CPMenuBarWindowBackgroundColor = nil,
|
||||
_CPMenuBarWindowFont = nil;
|
||||
|
||||
@implementation _CPMenuBarWindow : CPPanel
|
||||
{
|
||||
CPMenu _menu;
|
||||
CPView _highlightView;
|
||||
CPArray _menuItemViews;
|
||||
|
||||
CPMenuItem _trackingMenuItem;
|
||||
|
||||
CPImageView _iconImageView;
|
||||
CPTextField _titleField;
|
||||
|
||||
CPColor _textColor;
|
||||
CPColor _titleColor;
|
||||
|
||||
CPColor _textShadowColor;
|
||||
CPColor _titleShadowColor;
|
||||
|
||||
CPColor _highlightColor;
|
||||
CPColor _highlightTextColor;
|
||||
CPColor _highlightTextShadowColor;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self != [_CPMenuBarWindow class])
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
_CPMenuBarWindowFont = [CPFont boldSystemFontOfSize:12.0];
|
||||
}
|
||||
|
||||
+ (CPFont)font
|
||||
{
|
||||
return _CPMenuBarWindowFont;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
// This only shows up in browser land, so don't bother calculating metrics in desktop.
|
||||
var contentRect = [[CPPlatformWindow primaryPlatformWindow] contentBounds];
|
||||
|
||||
contentRect.size.height = MENUBAR_HEIGHT;
|
||||
|
||||
self = [super initWithContentRect:contentRect styleMask:CPBorderlessWindowMask];
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self setLevel:CPMainMenuWindowLevel];
|
||||
[self setAutoresizingMask:CPWindowWidthSizable];
|
||||
|
||||
var contentView = [self contentView];
|
||||
|
||||
[contentView setAutoresizesSubviews:NO];
|
||||
|
||||
[self setBecomesKeyOnlyIfNeeded:YES];
|
||||
|
||||
//
|
||||
_iconImageView = [[CPImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 16.0, 16.0)];
|
||||
|
||||
[contentView addSubview:_iconImageView];
|
||||
|
||||
_titleField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[_titleField setFont:[CPFont boldSystemFontOfSize:13.0]];
|
||||
[_titleField setAlignment:CPCenterTextAlignment];
|
||||
[_titleField setTextShadowOffset:CGSizeMake(0, 1)];
|
||||
|
||||
[contentView addSubview:_titleField];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
var bundleName = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPBundleName"];
|
||||
|
||||
if (![bundleName length])
|
||||
document.title = aTitle;
|
||||
else if ([aTitle length])
|
||||
document.title = aTitle + @" - " + bundleName;
|
||||
else
|
||||
document.title = bundleName;
|
||||
#endif
|
||||
|
||||
[_titleField setStringValue:aTitle];
|
||||
[_titleField sizeToFit];
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
- (void)setIconImage:(CPImage)anImage
|
||||
{
|
||||
[_iconImageView setImage:anImage];
|
||||
[_iconImageView setHidden:anImage == nil];
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
- (void)setIconImageAlphaValue:(float)anAlphaValue
|
||||
{
|
||||
[_iconImageView setAlphaValue:anAlphaValue];
|
||||
}
|
||||
|
||||
- (void)setColor:(CPColor)aColor
|
||||
{
|
||||
if (!aColor)
|
||||
{
|
||||
if (!_CPMenuBarWindowBackgroundColor)
|
||||
_CPMenuBarWindowBackgroundColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[_CPMenuBarWindow class]] pathForResource:@"_CPMenuBarWindow/_CPMenuBarWindowBackground.png"] size:CGSizeMake(1.0, 28.0)]];
|
||||
|
||||
[[self contentView] setBackgroundColor:_CPMenuBarWindowBackgroundColor];
|
||||
}
|
||||
else
|
||||
[[self contentView] setBackgroundColor:aColor];
|
||||
}
|
||||
|
||||
- (void)setTextColor:(CPColor)aColor
|
||||
{
|
||||
if (_textColor == aColor)
|
||||
return;
|
||||
|
||||
_textColor = aColor;
|
||||
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setTextColor:) withObject:_textColor];
|
||||
}
|
||||
|
||||
- (void)setTitleColor:(CPColor)aColor
|
||||
{
|
||||
if (_titleColor == aColor)
|
||||
return;
|
||||
|
||||
_titleColor = aColor;
|
||||
|
||||
[_titleField setTextColor:aColor ? aColor : [CPColor blackColor]];
|
||||
}
|
||||
|
||||
- (void)setTextShadowColor:(CPColor)aColor
|
||||
{
|
||||
if (_textShadowColor == aColor)
|
||||
return;
|
||||
|
||||
_textShadowColor = aColor;
|
||||
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setTextShadowColor:) withObject:_textShadowColor];
|
||||
}
|
||||
|
||||
- (void)setTitleShadowColor:(CPColor)aColor
|
||||
{
|
||||
if (_titleShadowColor == aColor)
|
||||
return;
|
||||
|
||||
_titleShadowColor = aColor;
|
||||
|
||||
[_titleField setTextShadowColor:aColor ? aColor : [CPColor whiteColor]];
|
||||
}
|
||||
|
||||
- (void)setHighlightColor:(CPColor)aColor
|
||||
{
|
||||
if (_highlightColor == aColor)
|
||||
return;
|
||||
|
||||
_highlightColor = aColor;
|
||||
}
|
||||
|
||||
- (void)setHighlightTextColor:(CPColor)aColor
|
||||
{
|
||||
if (_highlightTextColor == aColor)
|
||||
return;
|
||||
|
||||
_highlightTextColor = aColor;
|
||||
|
||||
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateColor:) withObject:_highlightTextColor];
|
||||
}
|
||||
|
||||
- (void)setHighlightTextShadowColor:(CPColor)aColor
|
||||
{
|
||||
if (_highlightTextShadowColor == aColor)
|
||||
return;
|
||||
|
||||
_highlightTextShadowColor = aColor;
|
||||
|
||||
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateShadowColor:) withObject:_highlightTextShadowColor];
|
||||
}
|
||||
|
||||
- (void)setMenu:(CPMenu)aMenu
|
||||
{
|
||||
if (_menu == aMenu)
|
||||
return;
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
if (_menu)
|
||||
{
|
||||
[defaultCenter
|
||||
removeObserver:self
|
||||
name:CPMenuDidAddItemNotification
|
||||
object:_menu];
|
||||
|
||||
[defaultCenter
|
||||
removeObserver:self
|
||||
name:CPMenuDidChangeItemNotification
|
||||
object:_menu];
|
||||
|
||||
[defaultCenter
|
||||
removeObserver:self
|
||||
name:CPMenuDidRemoveItemNotification
|
||||
object:_menu];
|
||||
|
||||
var items = [_menu itemArray],
|
||||
count = items.length;
|
||||
|
||||
while (count--)
|
||||
[[items[count] _menuItemView] removeFromSuperview];
|
||||
}
|
||||
|
||||
_menu = aMenu;
|
||||
|
||||
if (_menu)
|
||||
{
|
||||
[defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(menuDidAddItem:)
|
||||
name:CPMenuDidAddItemNotification
|
||||
object:_menu];
|
||||
|
||||
[defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(menuDidChangeItem:)
|
||||
name:CPMenuDidChangeItemNotification
|
||||
object:_menu];
|
||||
|
||||
[defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(menuDidRemoveItem:)
|
||||
name:CPMenuDidRemoveItemNotification
|
||||
object:_menu];
|
||||
}
|
||||
|
||||
_menuItemViews = [];
|
||||
|
||||
var contentView = [self contentView],
|
||||
items = [_menu itemArray],
|
||||
count = items.length;
|
||||
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
var item = items[index],
|
||||
menuItemView = [item _menuItemView];
|
||||
|
||||
_menuItemViews.push(menuItemView);
|
||||
|
||||
[menuItemView setTextColor:_textColor];
|
||||
[menuItemView setHidden:[item isHidden]];
|
||||
|
||||
[menuItemView synchronizeWithMenuItem];
|
||||
|
||||
[contentView addSubview:menuItemView];
|
||||
}
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
- (void)menuDidChangeItem:(CPNotification)aNotification
|
||||
{
|
||||
var menuItem = [_menu itemAtIndex:[[aNotification userInfo] objectForKey:@"CPMenuItemIndex"]],
|
||||
menuItemView = [menuItem _menuItemView];
|
||||
|
||||
[menuItemView setHidden:[menuItem isHidden]];
|
||||
[menuItemView synchronizeWithMenuItem];
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
- (void)menuDidAddItem:(CPNotification)aNotification
|
||||
{
|
||||
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"],
|
||||
menuItem = [_menu itemAtIndex:index],
|
||||
menuItemView = [menuItem _menuItemView];
|
||||
|
||||
[_menuItemViews insertObject:menuItemView atIndex:index];
|
||||
|
||||
[menuItemView setTextColor:_textColor];
|
||||
[menuItemView setHidden:[menuItem isHidden]];
|
||||
|
||||
[menuItemView synchronizeWithMenuItem];
|
||||
|
||||
[[self contentView] addSubview:menuItemView];
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
- (void)menuDidRemoveItem:(CPNotification)aNotification
|
||||
{
|
||||
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"],
|
||||
menuItemView = [_menuItemViews objectAtIndex:index];
|
||||
|
||||
[_menuItemViews removeObjectAtIndex:index];
|
||||
|
||||
[menuItemView removeFromSuperview];
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
var constraintRect = CGRectInset([[self platformWindow] visibleFrame], 5.0, 0.0);
|
||||
|
||||
constraintRect.size.height -= 5.0;
|
||||
|
||||
[[_CPMenuManager sharedMenuManager]
|
||||
beginTracking:anEvent
|
||||
menuContainer:self
|
||||
constraintRect:constraintRect
|
||||
callback:function(aMenuContainer, aMenu)
|
||||
{
|
||||
[aMenu _performActionOfHighlightedItemChain];
|
||||
[aMenu _highlightItemAtIndex:CPNotFound];
|
||||
}];
|
||||
}
|
||||
|
||||
- (CPFont)font
|
||||
{
|
||||
[CPFont systemFontOfSize:12.0];
|
||||
}
|
||||
|
||||
- (void)tile
|
||||
{
|
||||
var items = [_menu itemArray],
|
||||
index = 0,
|
||||
count = items.length,
|
||||
|
||||
x = MENUBAR_LEFT_MARGIN,
|
||||
y = 0.0,
|
||||
isLeftAligned = YES;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var item = items[index];
|
||||
|
||||
if ([item isSeparatorItem])
|
||||
{
|
||||
x = CGRectGetWidth([self frame]) - MENUBAR_RIGHT_MARGIN;
|
||||
isLeftAligned = NO;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([item isHidden])
|
||||
continue;
|
||||
|
||||
var menuItemView = [item _menuItemView],
|
||||
frame = [menuItemView frame];
|
||||
|
||||
if (isLeftAligned)
|
||||
{
|
||||
[menuItemView setFrame:CGRectMake(x, 0.0, CGRectGetWidth(frame), MENUBAR_HEIGHT)];
|
||||
|
||||
x += CGRectGetWidth([menuItemView frame]);
|
||||
}
|
||||
else
|
||||
{
|
||||
[menuItemView setFrame:CGRectMake(x - CGRectGetWidth(frame), 0.0, CGRectGetWidth(frame), MENUBAR_HEIGHT)];
|
||||
|
||||
x = CGRectGetMinX([menuItemView frame]);
|
||||
}
|
||||
}
|
||||
|
||||
var bounds = [[self contentView] bounds],
|
||||
titleFrame = [_titleField frame];
|
||||
|
||||
if ([_iconImageView isHidden])
|
||||
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(titleFrame)) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
|
||||
else
|
||||
{
|
||||
var iconFrame = [_iconImageView frame],
|
||||
iconWidth = CGRectGetWidth(iconFrame),
|
||||
totalWidth = iconWidth + CGRectGetWidth(titleFrame);
|
||||
|
||||
[_iconImageView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(iconFrame)) / 2.0)];
|
||||
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0 + iconWidth, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setFrame:(CGRect)aRect display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
|
||||
{
|
||||
var size = [self frame].size;
|
||||
|
||||
[super setFrame:aRect display:shouldDisplay animate:shouldAnimate];
|
||||
|
||||
if (!_CGSizeEqualToSize(size, aRect.size))
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPMenuBarWindow (CPMenuContainer)
|
||||
|
||||
- (BOOL)isMenuBar
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CGRect)globalFrame
|
||||
{
|
||||
return [self frame];
|
||||
}
|
||||
|
||||
- (_CPManagerScrollingState)scrollingStateForPoint:(CGPoint)aGlobalLocation
|
||||
{
|
||||
return _CPMenuManagerScrollingStateNone;
|
||||
}
|
||||
|
||||
- (CPInteger)itemIndexAtPoint:(CGPoint)aPoint
|
||||
{
|
||||
var items = [_menu itemArray],
|
||||
index = items.length;
|
||||
|
||||
while (index--)
|
||||
{
|
||||
var item = items[index];
|
||||
|
||||
if ([item isHidden] || [item isSeparatorItem])
|
||||
continue;
|
||||
|
||||
if (CGRectContainsPoint([self rectForItemAtIndex:index], aPoint))
|
||||
return index;
|
||||
}
|
||||
|
||||
return CPNotFound;
|
||||
}
|
||||
|
||||
- (CGRect)rectForItemAtIndex:(CPInteger)anIndex
|
||||
{
|
||||
var menuItem = [_menu itemAtIndex:anIndex === CPNotFound ? 0 : anIndex];
|
||||
|
||||
return [[menuItem _menuItemView] frame];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPMenuBarView : _CPMenuView
|
||||
{
|
||||
}
|
||||
|
||||
- (CGRect)rectForItemAtIndex:(int)anIndex
|
||||
{
|
||||
return [_menuItemViews[anIndex === CPNotFound ? 0 : anIndex] frame];
|
||||
}
|
||||
|
||||
- (int)itemIndexAtPoint:(CGPoint)aPoint
|
||||
{
|
||||
var bounds = [self bounds];
|
||||
|
||||
if (!CGRectContainsPoint(bounds, aPoint))
|
||||
return CPNotFound;
|
||||
|
||||
var x = aPoint.x,
|
||||
low = 0,
|
||||
high = _visibleMenuItemInfos.length - 1;
|
||||
|
||||
while (low <= high)
|
||||
{
|
||||
var middle = FLOOR(low + (high - low) / 2),
|
||||
info = _visibleMenuItemInfos[middle],
|
||||
frame = [info.view frame];
|
||||
|
||||
if (x < CGRectGetMinX(frame))
|
||||
high = middle - 1;
|
||||
|
||||
else if (x > CGRectGetMaxX(frame))
|
||||
low = middle + 1;
|
||||
|
||||
else
|
||||
return info.index;
|
||||
}
|
||||
|
||||
return CPNotFound;
|
||||
}
|
||||
|
||||
- (void)tile
|
||||
{
|
||||
var items = [_menu itemArray],
|
||||
index = 0,
|
||||
count = items.length,
|
||||
|
||||
x = MENUBAR_LEFT_MARGIN,
|
||||
y = 0.0,
|
||||
isLeftAligned = YES;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var item = items[index];
|
||||
|
||||
if ([item isSeparatorItem])
|
||||
{
|
||||
x = CGRectGetWidth([self frame]) - MENUBAR_RIGHT_MARGIN;
|
||||
isLeftAligned = NO;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([item isHidden])
|
||||
continue;
|
||||
|
||||
var menuItemView = [item _menuItemView],
|
||||
frame = [menuItemView frame];
|
||||
|
||||
if (isLeftAligned)
|
||||
{
|
||||
[menuItemView setFrameOrigin:CGPointMake(x, (MENUBAR_HEIGHT - 1.0 - CGRectGetHeight(frame)) / 2.0)];
|
||||
|
||||
x += CGRectGetWidth([menuItemView frame]) + MENUBAR_MARGIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
[menuItemView setFrameOrigin:CGPointMake(x - CGRectGetWidth(frame), (MENUBAR_HEIGHT - 1.0 - CGRectGetHeight(frame)) / 2.0)];
|
||||
|
||||
x = CGRectGetMinX([menuItemView frame]) - MENUBAR_MARGIN;
|
||||
}
|
||||
}
|
||||
|
||||
var bounds = [[self contentView] bounds],
|
||||
titleFrame = [_titleField frame];
|
||||
|
||||
if ([_iconImageView isHidden])
|
||||
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(titleFrame)) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
|
||||
else
|
||||
{
|
||||
var iconFrame = [_iconImageView frame],
|
||||
iconWidth = CGRectGetWidth(iconFrame),
|
||||
totalWidth = iconWidth + CGRectGetWidth(titleFrame);
|
||||
|
||||
[_iconImageView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(iconFrame)) / 2.0)];
|
||||
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0 + iconWidth, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,370 @@
|
||||
|
||||
#include "../CoreGraphics/CGGeometry.h"
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
|
||||
_CPMenuManagerScrollingStateUp = -1,
|
||||
_CPMenuManagerScrollingStateDown = 1,
|
||||
_CPMenuManagerScrollingStateNone = 0;
|
||||
|
||||
var STICKY_TIME_INTERVAL = 500;
|
||||
|
||||
var SharedMenuManager = nil;
|
||||
|
||||
@implementation _CPMenuManager: CPObject
|
||||
{
|
||||
CPTimeInterval _startTime;
|
||||
int _scrollingState;
|
||||
CGPoint _lastGlobalLocation;
|
||||
|
||||
CPView _lastMouseOverMenuView;
|
||||
|
||||
CGRect _constraintRect;
|
||||
CPMutableArray _menuContainerStack;
|
||||
|
||||
Function _trackingCallback;
|
||||
}
|
||||
|
||||
+ (_CPMenuManager)sharedMenuManager
|
||||
{
|
||||
if (!SharedMenuManager)
|
||||
SharedMenuManager = [[_CPMenuManager alloc] init];
|
||||
|
||||
return SharedMenuManager;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (SharedMenuManager)
|
||||
return SharedMenuManager;
|
||||
|
||||
return [super init];
|
||||
}
|
||||
|
||||
- (id)trackingMenuContainer
|
||||
{
|
||||
return _menuContainerStack[0];
|
||||
}
|
||||
|
||||
- (CPMenu)trackingMenu
|
||||
{
|
||||
return [[self trackingMenuContainer] menu];
|
||||
}
|
||||
|
||||
- (void)beginTracking:(CPEvent)anEvent
|
||||
menuContainer:(id)aMenuContainer
|
||||
constraintRect:(CGRect)aRect
|
||||
callback:(Function)aCallback
|
||||
{
|
||||
var menu = [aMenuContainer menu];
|
||||
|
||||
CPApp._activeMenu = menu;
|
||||
|
||||
_startTime = [anEvent timestamp];//new Date();
|
||||
_scrollingState = _CPMenuManagerScrollingStateNone;
|
||||
|
||||
_constraintRect = aRect;
|
||||
_menuContainerStack = [aMenuContainer];
|
||||
_trackingCallback = aCallback;
|
||||
|
||||
if (menu === [CPApp mainMenu])
|
||||
{
|
||||
var globalLocation = [anEvent globalLocation];
|
||||
|
||||
// Find which menu window the mouse is currently on top of
|
||||
var menuLocation = [aMenuContainer convertGlobalToBase:globalLocation];
|
||||
|
||||
// Find out the item the mouse is currently on top of
|
||||
var activeItemIndex = [aMenuContainer itemIndexAtPoint:menuLocation],
|
||||
activeItem = activeItemIndex !== CPNotFound ? [menu itemAtIndex:activeItemIndex] : nil;
|
||||
|
||||
_menuBarButtonItemIndex = activeItemIndex;
|
||||
_menuBarButtonMenuContainer = aMenuContainer;
|
||||
|
||||
if ([activeItem _isMenuBarButton])
|
||||
return [self trackMenuBarButtonEvent:anEvent];
|
||||
}
|
||||
|
||||
[self trackEvent:anEvent];
|
||||
}
|
||||
|
||||
- (void)trackEvent:(CPEvent)anEvent
|
||||
{
|
||||
var type = [anEvent type],
|
||||
trackingMenu = [self trackingMenu];
|
||||
|
||||
// Close Menu Event.
|
||||
if (type === CPAppKitDefined)
|
||||
return [self completeTracking]
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
// Periodic events don't have a valid location.
|
||||
var globalLocation = type === CPPeriodic ? _lastGlobalLocation : [anEvent globalLocation];
|
||||
|
||||
// Remember this for the next periodic event.
|
||||
_lastGlobalLocation = globalLocation;
|
||||
|
||||
// Find which menu window the mouse is currently on top of
|
||||
var activeMenuContainer = [self menuContainerForPoint:globalLocation],
|
||||
activeMenu = [activeMenuContainer menu],
|
||||
menuLocation = [activeMenuContainer convertGlobalToBase:globalLocation];
|
||||
|
||||
// Find out the item the mouse is currently on top of
|
||||
var activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
|
||||
activeItem = activeItemIndex !== CPNotFound ? [activeMenu itemAtIndex:activeItemIndex] : nil;
|
||||
|
||||
// If the item isn't enabled its as if we clicked on nothing.
|
||||
if (![activeItem isEnabled] || [activeItem _isMenuBarButton])
|
||||
{
|
||||
activeItemIndex = CPNotFound;
|
||||
activeItem = nil;
|
||||
}
|
||||
|
||||
var mouseOverMenuView = [activeItem view];
|
||||
|
||||
if (type === CPPeriodic)
|
||||
{
|
||||
if (_scrollingState === _CPMenuManagerScrollingStateUp)
|
||||
[activeMenuContainer scrollUp];
|
||||
|
||||
else if (_scrollingState === _CPMenuManagerScrollingStateDown)
|
||||
[activeMenuContainer scrollDown];
|
||||
}
|
||||
|
||||
// If we're over a custom menu view...
|
||||
if (mouseOverMenuView)
|
||||
{
|
||||
if (!_lastMouseOverMenuView)
|
||||
[activeMenu _highlightItemAtIndex:CPNotFound];
|
||||
|
||||
if (_lastMouseOverMenuView != mouseOverMenuView)
|
||||
{
|
||||
[mouseOverMenuView mouseExited:anEvent];
|
||||
// FIXME: Possibly multiple of these?
|
||||
[_lastMouseOverMenuView mouseEntered:anEvent];
|
||||
|
||||
_lastMouseOverMenuView = mouseOverMenuView;
|
||||
}
|
||||
|
||||
var menuContainerWindow = activeMenuContainer;
|
||||
|
||||
if (![menuContainerWindow isKindOfClass:[CPWindow class]])
|
||||
menuContainerWindow = [menuContainerWindow window];
|
||||
|
||||
[menuContainerWindow
|
||||
sendEvent:[CPEvent mouseEventWithType:type location:menuLocation modifierFlags:[anEvent modifierFlags]
|
||||
timestamp:[anEvent timestamp]
|
||||
windowNumber:menuContainerWindow
|
||||
context:nil
|
||||
eventNumber:0
|
||||
clickCount:[anEvent clickCount]
|
||||
pressure:[anEvent pressure]]];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_lastMouseOverMenuView)
|
||||
{
|
||||
[_lastMouseOverMenuView mouseExited:anEvent];
|
||||
_lastMouseOverMenuView = nil;
|
||||
}
|
||||
|
||||
[activeMenu _highlightItemAtIndex:activeItemIndex];
|
||||
|
||||
if (type === CPMouseMoved || type === CPLeftMouseDragged || type === CPLeftMouseDown)
|
||||
{
|
||||
var oldScrollingState = _scrollingState;
|
||||
|
||||
_scrollingState = [activeMenuContainer scrollingStateForPoint:globalLocation];
|
||||
|
||||
if (_scrollingState !== oldScrollingState)
|
||||
{
|
||||
if (_scrollingState === _CPMenuManagerScrollingStateNone)
|
||||
[CPEvent stopPeriodicEvents];
|
||||
|
||||
else if (oldScrollingState === _CPMenuManagerScrollingStateNone)
|
||||
[CPEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.04];
|
||||
}
|
||||
}
|
||||
else if (type === CPLeftMouseUp && ([anEvent timestamp] - _startTime > STICKY_TIME_INTERVAL))
|
||||
[trackingMenu cancelTracking];
|
||||
}
|
||||
|
||||
// If the item has a submenu, show it.
|
||||
if ([activeItem hasSubmenu])// && [activeItem action] === @selector(submenuAction:))
|
||||
{
|
||||
var activeItemRect = [activeMenuContainer rectForItemAtIndex:activeItemIndex];
|
||||
|
||||
if ([activeMenuContainer isMenuBar])
|
||||
var newMenuOrigin = CGPointMake(CGRectGetMinX(activeItemRect), CGRectGetMaxY(activeItemRect));
|
||||
else
|
||||
var newMenuOrigin = CGPointMake(CGRectGetMaxX(activeItemRect), CGRectGetMinY(activeItemRect));
|
||||
|
||||
newMenuOrigin = [activeMenuContainer convertBaseToGlobal:newMenuOrigin];
|
||||
|
||||
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
|
||||
}
|
||||
|
||||
// This handles both the case where we've moved away from the menu, and where
|
||||
// we've moved to an item without a submenu.
|
||||
else
|
||||
[self showMenu:nil fromMenu:activeMenu atPoint:CGPointMakeZero()];
|
||||
}
|
||||
|
||||
- (void)trackMenuBarButtonEvent:(CPEvent)anEvent
|
||||
{
|
||||
var type = [anEvent type];
|
||||
|
||||
if (type === CPAppKitDefined)
|
||||
return [self completeTracking];
|
||||
|
||||
var globalLocation = [anEvent globalLocation];
|
||||
|
||||
// Find which menu window the mouse is currently on top of
|
||||
var menu = [self trackingMenu],
|
||||
trackingMenuContainer = [self trackingMenuContainer],
|
||||
menuLocation = [trackingMenuContainer convertGlobalToBase:globalLocation];
|
||||
|
||||
if ([trackingMenuContainer itemIndexAtPoint:menuLocation] === _menuBarButtonItemIndex)
|
||||
[menu _highlightItemAtIndex:_menuBarButtonItemIndex];
|
||||
|
||||
else
|
||||
[menu _highlightItemAtIndex:CPNotFound];
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackMenuBarButtonEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
[menu cancelTracking];
|
||||
}
|
||||
|
||||
- (void)completeTracking
|
||||
{
|
||||
var trackingMenu = [self trackingMenu];
|
||||
|
||||
// Stop all periodic events at this point.
|
||||
[CPEvent stopPeriodicEvents];
|
||||
|
||||
// Get the highlighted item from the original menu.
|
||||
var highlightedItem = [trackingMenu highlightedItem];
|
||||
|
||||
// Hide all submenus.
|
||||
[self showMenu:nil fromMenu:trackingMenu atPoint:nil];
|
||||
|
||||
var delegate = [trackingMenu delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuDidClose:)])
|
||||
[delegate menuDidClose:trackingMenu];
|
||||
|
||||
if (_trackingCallback)
|
||||
_trackingCallback([self trackingMenuContainer], trackingMenu);
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPMenuDidEndTrackingNotification
|
||||
object:trackingMenu];
|
||||
|
||||
CPApp._activeMenu = nil;
|
||||
}
|
||||
|
||||
- (id)menuContainerForPoint:(float)aGlobalLocation
|
||||
{
|
||||
var count = [_menuContainerStack count],
|
||||
firstMenuContainer = _menuContainerStack[0];
|
||||
|
||||
// Trivial case.
|
||||
if (count === 1)
|
||||
return firstMenuContainer;
|
||||
|
||||
var firstMenuWindowIndex = 0,
|
||||
lastMenuWindowIndex = count - 1;
|
||||
|
||||
// If the first menu container is a bar, then it has to fall strictly within its bounds.
|
||||
if ([firstMenuContainer isMenuBar])
|
||||
{
|
||||
if (CGRectContainsPoint([firstMenuContainer globalFrame], aGlobalLocation))
|
||||
return firstMenuContainer;
|
||||
|
||||
firstMenuWindowIndex = 1;
|
||||
}
|
||||
|
||||
var index = count,
|
||||
x = aGlobalLocation.x,
|
||||
closerDeltaX = Infinity,
|
||||
closerMenuContainer = nil;
|
||||
|
||||
while (index-- > firstMenuWindowIndex)
|
||||
{
|
||||
var menuContainer = _menuContainerStack[index],
|
||||
menuContainerFrame = [menuContainer globalFrame],
|
||||
menuContainerMinX = _CGRectGetMinX(menuContainerFrame),
|
||||
menuContainerMaxX = _CGRectGetMaxX(menuContainerFrame);
|
||||
|
||||
// If within the x bounds of this menu container, return it.
|
||||
if (x < menuContainerMaxX && x >= menuContainerMinX)
|
||||
return menuContainer;
|
||||
|
||||
// If this is either the first or last menu *window*, check to see how close we are to it.
|
||||
if (index === firstMenuWindowIndex || index === lastMenuWindowIndex)
|
||||
{
|
||||
var deltaX = ABS(x < menuContainerMinX ? menuContainerMinX - x : menuContainerMaxX - x);
|
||||
|
||||
if (deltaX < closerDeltaX)
|
||||
{
|
||||
closerMenuContainer = menuContainer;
|
||||
closerDeltaX = deltaX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closerMenuContainer;
|
||||
}
|
||||
|
||||
- (void)showMenu:(CPMenu)newMenu fromMenu:(CPMenu)baseMenu atPoint:(CGPoint)aGlobalLocation
|
||||
{
|
||||
var count = _menuContainerStack.length,
|
||||
index = count;
|
||||
|
||||
// Hide all menus up to the base menu...
|
||||
while (index--)
|
||||
{
|
||||
var menuContainer = _menuContainerStack[index],
|
||||
menu = [menuContainer menu];
|
||||
|
||||
// If we reach the base menu, or this menu is already being shown, break.
|
||||
if (menu === baseMenu)
|
||||
break;
|
||||
|
||||
// If this menu is already being shown, unhighlight and return.
|
||||
if (menu === newMenu)//&& [menu supermenu] === baseMenu)
|
||||
return [newMenu _highlightItemAtIndex:CPNotFound];
|
||||
|
||||
[menuContainer orderOut:self];
|
||||
[menuContainer setMenu:nil];
|
||||
|
||||
[_CPMenuWindow poolMenuWindow:menuContainer];
|
||||
[_menuContainerStack removeObjectAtIndex:index];
|
||||
}
|
||||
|
||||
if (!newMenu)
|
||||
return;
|
||||
|
||||
// Unhighlight any previously highlighted item.
|
||||
[newMenu _highlightItemAtIndex:CPNotFound];
|
||||
|
||||
var menuWindow = [_CPMenuWindow menuWindowWithMenu:newMenu font:[_menuContainerStack[0] font]];
|
||||
|
||||
[_menuContainerStack addObject:menuWindow];
|
||||
|
||||
[menuWindow setConstraintRect:_constraintRect];
|
||||
|
||||
// If our parent menu is a menu bar...
|
||||
if (baseMenu === [self trackingMenu] && [[self trackingMenuContainer] isMenuBar])
|
||||
[menuWindow setBackgroundStyle:_CPMenuWindowMenuBarBackgroundStyle];
|
||||
else
|
||||
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
|
||||
|
||||
[menuWindow setFrameOrigin:aGlobalLocation];
|
||||
[menuWindow orderFront:self];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,548 @@
|
||||
|
||||
#include "../CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
var _CPMenuWindowPool = [],
|
||||
_CPMenuWindowPoolCapacity = 5,
|
||||
|
||||
_CPMenuWindowBackgroundColors = [];
|
||||
|
||||
_CPMenuWindowMenuBarBackgroundStyle = 0;
|
||||
_CPMenuWindowPopUpBackgroundStyle = 1;
|
||||
_CPMenuWindowAttachedMenuBackgroundStyle = 2;
|
||||
|
||||
var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
TOP_MARGIN = 5.0,
|
||||
LEFT_MARGIN = 1.0,
|
||||
RIGHT_MARGIN = 1.0,
|
||||
BOTTOM_MARGIN = 5.0,
|
||||
|
||||
SCROLL_INDICATOR_HEIGHT = 16.0;
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
@implementation _CPMenuWindow : CPWindow
|
||||
{
|
||||
_CPMenuView _menuView;
|
||||
CPClipView _menuClipView;
|
||||
|
||||
CPImageView _moreAboveView;
|
||||
CPImageView _moreBelowView;
|
||||
|
||||
CGRect _unconstrainedFrame;
|
||||
CGRect _constraintRect;
|
||||
}
|
||||
|
||||
+ (id)menuWindowWithMenu:(CPMenu)aMenu font:(CPFont)aFont
|
||||
{
|
||||
var menuWindow = nil;
|
||||
|
||||
if (_CPMenuWindowPool.length)
|
||||
{
|
||||
menuWindow = _CPMenuWindowPool.pop();
|
||||
|
||||
// Do this so that coordinates will be accurate.
|
||||
[menuWindow setFrameOrigin:CGPointMakeZero()];
|
||||
}
|
||||
else
|
||||
menuWindow = [[_CPMenuWindow alloc] init];
|
||||
|
||||
[menuWindow setFont:aFont];
|
||||
[menuWindow setMenu:aMenu];
|
||||
[menuWindow setMinWidth:[aMenu minimumWidth]];
|
||||
|
||||
return menuWindow;
|
||||
}
|
||||
|
||||
+ (void)poolMenuWindow:(_CPMenuWindow)aMenuWindow
|
||||
{
|
||||
if (!aMenuWindow || _CPMenuWindowPool.length >= _CPMenuWindowPoolCapacity)
|
||||
return;
|
||||
|
||||
_CPMenuWindowPool.push(aMenuWindow);
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self != [_CPMenuWindow class])
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
_CPMenuWindowMoreAboveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreAbove.png"] size:CGSizeMake(38.0, 18.0)];
|
||||
_CPMenuWindowMoreBelowImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreBelow.png"] size:CGSizeMake(38.0, 18.0)];
|
||||
}
|
||||
|
||||
- (id)initWithContentRect:(CGRect)aRect styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
_constraintRect = _CGRectMakeZero();
|
||||
_unconstrainedFrame = _CGRectMakeZero();
|
||||
|
||||
self = [super initWithContentRect:aRect styleMask:CPBorderlessWindowMask];
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self setLevel:CPPopUpMenuWindowLevel];
|
||||
[self setHasShadow:YES];
|
||||
[self setShadowStyle:CPMenuWindowShadowStyle];
|
||||
[self setAcceptsMouseMovedEvents:YES];
|
||||
|
||||
var contentView = [self contentView];
|
||||
|
||||
_menuView = [[_CPMenuView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
_menuClipView = [[CPClipView alloc] initWithFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, 0.0, 0.0)];
|
||||
[_menuClipView setDocumentView:_menuView];
|
||||
|
||||
[contentView addSubview:_menuClipView];
|
||||
|
||||
_moreAboveView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[_moreAboveView setImage:_CPMenuWindowMoreAboveImage];
|
||||
[_moreAboveView setFrameSize:[_CPMenuWindowMoreAboveImage size]];
|
||||
|
||||
[contentView addSubview:_moreAboveView];
|
||||
|
||||
_moreBelowView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[_moreBelowView setImage:_CPMenuWindowMoreBelowImage];
|
||||
[_moreBelowView setFrameSize:[_CPMenuWindowMoreBelowImage size]];
|
||||
|
||||
[contentView addSubview:_moreBelowView];
|
||||
|
||||
[self setShadowStyle:CPWindowShadowStyleMenu];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (float)_standardLeftMargin
|
||||
{
|
||||
return LEFT_MARGIN;
|
||||
}
|
||||
|
||||
- (void)setFont:(CPFont)aFont
|
||||
{
|
||||
[_menuView setFont:aFont];
|
||||
}
|
||||
|
||||
- (CPFont)font
|
||||
{
|
||||
return [_menuView font];
|
||||
}
|
||||
|
||||
+ (CPColor)backgroundColorForBackgroundStyle:(_CPMenuWindowBackgroundStyle)aBackgroundStyle
|
||||
{
|
||||
var color = _CPMenuWindowBackgroundColors[aBackgroundStyle];
|
||||
|
||||
if (!color)
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[self class]];
|
||||
|
||||
if (aBackgroundStyle == _CPMenuWindowPopUpBackgroundStyle)
|
||||
color = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded0.png"] size:CGSizeMake(4.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow1.png"] size:CGSizeMake(1.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded2.png"] size:CGSizeMake(4.0, 4.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
|
||||
]]];
|
||||
|
||||
else if (aBackgroundStyle == _CPMenuWindowMenuBarBackgroundStyle)
|
||||
color = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 0.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 0.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 0.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
|
||||
]]];
|
||||
|
||||
_CPMenuWindowBackgroundColors[aBackgroundStyle] = color;
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
- (void)setBackgroundStyle:(_CPMenuWindowBackgroundStyle)aBackgroundStyle
|
||||
{
|
||||
[self setBackgroundColor:[[self class] backgroundColorForBackgroundStyle:aBackgroundStyle]];
|
||||
}
|
||||
|
||||
- (void)setMenu:(CPMenu)aMenu
|
||||
{
|
||||
[aMenu _setMenuWindow:self];
|
||||
[_menuView setMenu:aMenu];
|
||||
|
||||
var menuViewSize = [_menuView frame].size;
|
||||
|
||||
[self setFrameSize:CGSizeMake(LEFT_MARGIN + menuViewSize.width + RIGHT_MARGIN, TOP_MARGIN + menuViewSize.height + BOTTOM_MARGIN)];
|
||||
|
||||
[_menuView scrollPoint:CGPointMake(0.0, 0.0)];
|
||||
[_menuClipView setFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, menuViewSize.width, menuViewSize.height)];
|
||||
}
|
||||
|
||||
- (void)setMinWidth:(float)aWidth
|
||||
{
|
||||
var size = [self unconstrainedFrame].size;
|
||||
|
||||
[self setFrameSize:CGSizeMake(MAX(size.width, aWidth), size.height)];
|
||||
}
|
||||
|
||||
- (CPMenu)menu
|
||||
{
|
||||
return [_menuView menu];
|
||||
}
|
||||
|
||||
- (void)orderFront:(id)aSender
|
||||
{
|
||||
[self setFrame:_unconstrainedFrame];
|
||||
|
||||
[super orderFront:aSender];
|
||||
}
|
||||
|
||||
- (void)setConstraintRect:(CGRect)aRect
|
||||
{
|
||||
_constraintRect = aRect;
|
||||
|
||||
[self setFrame:_unconstrainedFrame];
|
||||
}
|
||||
|
||||
- (CGRect)unconstrainedFrame
|
||||
{
|
||||
return _CGRectMakeCopy(_unconstrainedFrame);
|
||||
}
|
||||
|
||||
// We need this because if not this will call setFrame: with -frame instead of -unconstrainedFrame, turning
|
||||
// the constrained frame into the unconstrained frame.
|
||||
- (void)setFrameOrigin:(CGPoint)aPoint
|
||||
{
|
||||
[super setFrame:_CGRectMake(aPoint.x, aPoint.y, _CGRectGetWidth(_unconstrainedFrame), _CGRectGetHeight(_unconstrainedFrame))];
|
||||
}
|
||||
|
||||
- (void)setFrameSize:(CGSize)aSize
|
||||
{
|
||||
[super setFrame:_CGRectMake(_CGRectGetMinX(_unconstrainedFrame), _CGRectGetMinY(_unconstrainedFrame), aSize.width, aSize.height)];
|
||||
}
|
||||
|
||||
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
|
||||
{
|
||||
// FIXME: There are integral window issues with platform windows.
|
||||
// FIXME: This gets called far too often.
|
||||
_unconstrainedFrame = _CGRectMakeCopy(aFrame);
|
||||
|
||||
var constrainedFrame = CGRectIntersection(_unconstrainedFrame, _constraintRect);
|
||||
|
||||
// We don't want to simply intersect the visible frame and the unconstrained frame.
|
||||
// We should be allowing as much of the width to fit as possible (pushing back and forward).
|
||||
constrainedFrame.origin.x = CGRectGetMinX(_unconstrainedFrame);
|
||||
constrainedFrame.size.width = CGRectGetWidth(_unconstrainedFrame);
|
||||
|
||||
if (CGRectGetWidth(constrainedFrame) > CGRectGetWidth(_constraintRect))
|
||||
constrainedFrame.size.width = CGRectGetWidth(_constraintRect);
|
||||
|
||||
if (CGRectGetMaxX(constrainedFrame) > CGRectGetMaxX(_constraintRect))
|
||||
constrainedFrame.origin.x -= CGRectGetMaxX(constrainedFrame) - CGRectGetMaxX(_constraintRect);
|
||||
|
||||
if (CGRectGetMinX(constrainedFrame) < CGRectGetMinX(_constraintRect))
|
||||
constrainedFrame.origin.x = CGRectGetMinX(_constraintRect);
|
||||
|
||||
[super setFrame:constrainedFrame display:shouldDisplay animate:shouldAnimate];
|
||||
|
||||
// This needs to happen before changing the frame.
|
||||
var menuViewOrigin = CGPointMake(CGRectGetMinX(aFrame) + LEFT_MARGIN, CGRectGetMinY(aFrame) + TOP_MARGIN),
|
||||
moreAbove = menuViewOrigin.y < CGRectGetMinY(constrainedFrame) + TOP_MARGIN,
|
||||
moreBelow = menuViewOrigin.y + CGRectGetHeight([_menuView frame]) > CGRectGetMaxY(constrainedFrame) - BOTTOM_MARGIN,
|
||||
|
||||
topMargin = TOP_MARGIN,
|
||||
bottomMargin = BOTTOM_MARGIN,
|
||||
|
||||
contentView = [self contentView],
|
||||
bounds = [contentView bounds];
|
||||
|
||||
if (moreAbove)
|
||||
{
|
||||
topMargin += SCROLL_INDICATOR_HEIGHT;
|
||||
|
||||
var frame = [_moreAboveView frame];
|
||||
|
||||
[_moreAboveView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(frame)) / 2.0, (TOP_MARGIN + SCROLL_INDICATOR_HEIGHT - CGRectGetHeight(frame)) / 2.0)];
|
||||
}
|
||||
|
||||
[_moreAboveView setHidden:!moreAbove];
|
||||
|
||||
if (moreBelow)
|
||||
{
|
||||
bottomMargin += SCROLL_INDICATOR_HEIGHT;
|
||||
|
||||
[_moreBelowView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth([_moreBelowView frame])) / 2.0, CGRectGetHeight(bounds) - SCROLL_INDICATOR_HEIGHT - BOTTOM_MARGIN)];
|
||||
}
|
||||
|
||||
[_moreBelowView setHidden:!moreBelow];
|
||||
|
||||
var clipFrame = CGRectMake(LEFT_MARGIN, topMargin, CGRectGetWidth(constrainedFrame) - LEFT_MARGIN - RIGHT_MARGIN, CGRectGetHeight(constrainedFrame) - topMargin - bottomMargin)
|
||||
|
||||
[_menuClipView setFrame:clipFrame];
|
||||
[_menuView setFrameSize:CGSizeMake(CGRectGetWidth(clipFrame), CGRectGetHeight([_menuView frame]))];
|
||||
|
||||
[_menuView scrollPoint:CGPointMake(0.0, [self convertBaseToGlobal:clipFrame.origin].y - menuViewOrigin.y)];
|
||||
}
|
||||
|
||||
- (BOOL)hasMinimumNumberOfVisibleItems
|
||||
{
|
||||
var visibleRect = [_menuView visibleRect];
|
||||
|
||||
// Clearly if the entire view isn't visible the minimum won't be visible.
|
||||
if (CGRectIsEmpty(visibleRect))
|
||||
return NO;
|
||||
|
||||
var numberOfUnhiddenItems = [_menuView numberOfUnhiddenItems],
|
||||
minimumNumberOfVisibleItems = MIN(numberOfUnhiddenItems, 3),
|
||||
count = 0,
|
||||
index = [_menuView itemIndexAtPoint:[_menuView convertPoint:[_menuClipView frame].origin fromView:nil]];
|
||||
|
||||
for (; index < numberOfUnhiddenItems && count < minimumNumberOfVisibleItems; ++index)
|
||||
{
|
||||
var itemRect = [_menuView rectForUnhiddenItemAtIndex:index],
|
||||
visibleItemRect = CGRectIntersection(visibleRect, itemRect);
|
||||
|
||||
// As soon as we get to the first unhidden item that is no longer visible, stop.
|
||||
if (CGRectIsEmpty(visibleItemRect))
|
||||
break;
|
||||
|
||||
// If the item is *completely* visible, count it.
|
||||
if (CGRectEqualToRect(visibleItemRect, itemRect))
|
||||
++count;
|
||||
}
|
||||
|
||||
return count >= minimumNumberOfVisibleItems;
|
||||
}
|
||||
|
||||
- (BOOL)canScrollUp
|
||||
{
|
||||
return ![_moreAboveView isHidden];
|
||||
}
|
||||
|
||||
- (BOOL)canScrollDown
|
||||
{
|
||||
return ![_moreBelowView isHidden];
|
||||
}
|
||||
|
||||
- (BOOL)canScroll
|
||||
{
|
||||
return [self canScrollUp] || [self canScrollDown];
|
||||
}
|
||||
|
||||
- (void)scrollUp
|
||||
{
|
||||
if (CGRectGetMinY(_unconstrainedFrame) >= CGRectGetMinY(_constraintRect))
|
||||
return;
|
||||
|
||||
_unconstrainedFrame.origin.y += 10;
|
||||
|
||||
[self setFrame:_unconstrainedFrame];
|
||||
}
|
||||
|
||||
- (void)scrollDown
|
||||
{
|
||||
if (CGRectGetMaxY(_unconstrainedFrame) <= CGRectGetHeight(_constraintRect))
|
||||
return;
|
||||
|
||||
_unconstrainedFrame.origin.y -= 10;
|
||||
|
||||
[self setFrame:_unconstrainedFrame];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPMenuWindow (CPMenuContainer)
|
||||
|
||||
- (CGRect)globalFrame
|
||||
{
|
||||
return [self frame];
|
||||
}
|
||||
|
||||
- (BOOL)isMenuBar
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (_CPManagerScrollingState)scrollingStateForPoint:(CGPoint)aGlobalLocation
|
||||
{
|
||||
var frame = [self frame];
|
||||
|
||||
if (![self canScroll])
|
||||
return _CPMenuManagerScrollingStateNone;
|
||||
|
||||
// If we're at or above of the top scroll indicator...
|
||||
if (aGlobalLocation.y < CGRectGetMinY(frame) + TOP_MARGIN + SCROLL_INDICATOR_HEIGHT)
|
||||
return _CPMenuManagerScrollingStateUp;
|
||||
|
||||
// If we're at or below the bottom scroll indicator...
|
||||
if (aGlobalLocation.y > CGRectGetMaxY(frame) - BOTTOM_MARGIN - SCROLL_INDICATOR_HEIGHT)
|
||||
return _CPMenuManagerScrollingStateDown;
|
||||
|
||||
return _CPMenuManagerScrollingStateNone;
|
||||
}
|
||||
|
||||
- (float)deltaYForItemAtIndex:(int)anIndex
|
||||
{
|
||||
return TOP_MARGIN + CGRectGetMinY([_menuView rectForItemAtIndex:anIndex]);
|
||||
}
|
||||
|
||||
- (CGPoint)rectForItemAtIndex:(int)anIndex
|
||||
{
|
||||
return [_menuView convertRect:[_menuView rectForItemAtIndex:anIndex] toView:nil];
|
||||
}
|
||||
|
||||
- (int)itemIndexAtPoint:(CGPoint)aPoint
|
||||
{
|
||||
// Don't return indexes of items that aren't visible.
|
||||
if (!CGRectContainsPoint([_menuClipView bounds], [_menuClipView convertPoint:aPoint fromView:nil]))
|
||||
return NO;
|
||||
|
||||
return [_menuView itemIndexAtPoint:[_menuView convertPoint:aPoint fromView:nil]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
|
||||
@implementation _CPMenuView : CPView
|
||||
{
|
||||
CPArray _menuItemViews;
|
||||
CPArray _visibleMenuItemInfos;
|
||||
|
||||
CPFont _font @accessors(property=font);
|
||||
}
|
||||
|
||||
- (unsigned)numberOfUnhiddenItems
|
||||
{
|
||||
return _visibleMenuItemInfos.length;
|
||||
}
|
||||
|
||||
- (CGRect)rectForUnhiddenItemAtIndex:(int)anIndex
|
||||
{
|
||||
return [self rectForItemAtIndex:_visibleMenuItemInfos[anIndex].index];
|
||||
}
|
||||
|
||||
- (CGRect)rectForItemAtIndex:(int)anIndex
|
||||
{
|
||||
return [_menuItemViews[anIndex === CPNotFound ? 0 : anIndex] frame];
|
||||
}
|
||||
|
||||
- (int)itemIndexAtPoint:(CGPoint)aPoint
|
||||
{
|
||||
var x = aPoint.x,
|
||||
bounds = [self bounds];
|
||||
|
||||
if (x < CGRectGetMinX(bounds) || x > CGRectGetMaxX(bounds))
|
||||
return CPNotFound;
|
||||
|
||||
var y = aPoint.y,
|
||||
low = 0,
|
||||
high = _visibleMenuItemInfos.length - 1;
|
||||
|
||||
while (low <= high)
|
||||
{
|
||||
var middle = FLOOR(low + (high - low) / 2),
|
||||
info = _visibleMenuItemInfos[middle]
|
||||
frame = [info.view frame];
|
||||
|
||||
if (y < CGRectGetMinY(frame))
|
||||
high = middle - 1;
|
||||
|
||||
else if (y > CGRectGetMaxY(frame))
|
||||
low = middle + 1;
|
||||
|
||||
else
|
||||
return info.index;
|
||||
}
|
||||
|
||||
return CPNotFound;
|
||||
}
|
||||
|
||||
- (void)tile
|
||||
{
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
|
||||
_menuItemViews = [];
|
||||
_visibleMenuItemInfos = [];
|
||||
|
||||
var menu = [self menu];
|
||||
|
||||
if (!menu)
|
||||
return;
|
||||
|
||||
var items = [menu itemArray],
|
||||
index = 0,
|
||||
count = [items count],
|
||||
maxWidth = 0,
|
||||
y = 0,
|
||||
showsStateColumn = [menu showsStateColumn];
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var item = items[index],
|
||||
view = [item _menuItemView];
|
||||
|
||||
_menuItemViews.push(view);
|
||||
|
||||
if ([item isHidden])
|
||||
continue;
|
||||
|
||||
_visibleMenuItemInfos.push({ view:view, index:index });
|
||||
|
||||
[view setFont:_font];
|
||||
[view setShowsStateColumn:showsStateColumn];
|
||||
[view synchronizeWithMenuItem];
|
||||
|
||||
[view setFrameOrigin:CGPointMake(0.0, y)];
|
||||
|
||||
[self addSubview:view];
|
||||
|
||||
var size = [view minSize],
|
||||
width = size.width;
|
||||
|
||||
if (maxWidth < width)
|
||||
maxWidth = width;
|
||||
|
||||
y += size.height;
|
||||
}
|
||||
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
var view = _menuItemViews[index];
|
||||
|
||||
[view setFrameSize:CGSizeMake(maxWidth, CGRectGetHeight([view frame]))];
|
||||
}
|
||||
|
||||
[self setAutoresizesSubviews:NO];
|
||||
[self setFrameSize:CGSizeMake(maxWidth, y)];
|
||||
[self setAutoresizesSubviews:YES];
|
||||
}
|
||||
|
||||
- (void)setMenu:(CPMenu)aMenu
|
||||
{
|
||||
[super setMenu:aMenu];
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -24,9 +24,10 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@import <AppKit/CPImage.j>
|
||||
@import <AppKit/CPMenu.j>
|
||||
@import <AppKit/CPView.j>
|
||||
@import "CPImage.j"
|
||||
@import "CPMenu.j"
|
||||
@import "CPView.j"
|
||||
@import "_CPMenuItemView.j"
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -78,6 +79,11 @@
|
||||
_CPMenuItemView _menuItemView;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initWithTitle:@"" action:nil keyEquivalent:nil];
|
||||
}
|
||||
|
||||
/*!
|
||||
Initializes the menu item with a title, action, and keyboard equivalent.
|
||||
@param aTitle the menu item's title
|
||||
@@ -103,7 +109,9 @@
|
||||
|
||||
_keyEquivalent = aKeyEquivalent || @"";
|
||||
_keyEquivalentModifierMask = CPPlatformActionKeyMask;
|
||||
|
||||
|
||||
_indentationLevel = 0;
|
||||
|
||||
_mnemonicLocation = CPNotFound;
|
||||
}
|
||||
|
||||
@@ -443,20 +451,32 @@ CPOffState
|
||||
*/
|
||||
- (void)setSubmenu:(CPMenu)aMenu
|
||||
{
|
||||
var supermenu = [_submenu supermenu];
|
||||
|
||||
if (supermenu == self)
|
||||
if (_submenu === aMenu)
|
||||
return;
|
||||
|
||||
|
||||
var supermenu = [_submenu supermenu];
|
||||
|
||||
if (supermenu)
|
||||
return alert("bad");
|
||||
|
||||
[_submenu setSupermenu:_menu];
|
||||
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
reason: @"Can't add submenu \"" + [aMenu title] + "\" to item \"" + [self title] + "\", because it is already submenu of \"" + [[aMenu supermenu] title] + "\""];
|
||||
|
||||
_submenu = aMenu;
|
||||
|
||||
|
||||
if (_submenu)
|
||||
{
|
||||
[_submenu setSupermenu:_menu];
|
||||
|
||||
[self setTarget:_menu];
|
||||
[self setAction:@selector(submenuAction:)];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setTarget:nil];
|
||||
[self setAction:NULL];
|
||||
}
|
||||
|
||||
[_menuItemView setDirty];
|
||||
|
||||
|
||||
[_menu itemChanged:self];
|
||||
}
|
||||
|
||||
@@ -565,6 +585,43 @@ CPControlKeyMask
|
||||
return _keyEquivalentModifierMask;
|
||||
}
|
||||
|
||||
- (CPString)keyEquivalentStringRepresentation
|
||||
{
|
||||
if (![_keyEquivalent length])
|
||||
return @"";
|
||||
|
||||
var string = _keyEquivalent.toUpperCase(),
|
||||
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || string === _keyEquivalent;
|
||||
|
||||
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
|
||||
{
|
||||
if (_keyEquivalentModifierMask & CPCommandKeyMask)
|
||||
string = "⌘" + string;
|
||||
|
||||
if (needsShift)
|
||||
string = "⇧" + string;
|
||||
|
||||
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
|
||||
string = "⌥" + string;
|
||||
|
||||
if (_keyEquivalentModifierMask & CPControlKeyMask)
|
||||
string = "^" + string;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (needsShift)
|
||||
string = "Shift-" + string;
|
||||
|
||||
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
|
||||
string = "Alt-" + string;
|
||||
|
||||
if (_keyEquivalentModifierMask & CPControlKeyMask || _keyEquivalentModifierMask & CPCommandKeyMask)
|
||||
string = "Ctrl-" + string;
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
// Managing Mnemonics
|
||||
/*!
|
||||
Sets the index of the mnemonic character in the title. The character
|
||||
@@ -638,7 +695,7 @@ CPControlKeyMask
|
||||
- (void)setIndentationLevel:(unsigned)aLevel
|
||||
{
|
||||
if (aLevel < 0)
|
||||
[CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than 0."];
|
||||
[CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than or equal to 0."];
|
||||
|
||||
_indentationLevel = MIN(15, aLevel);
|
||||
}
|
||||
@@ -737,28 +794,43 @@ CPControlKeyMask
|
||||
return _menuItemView;
|
||||
}
|
||||
|
||||
- (BOOL)_isSelectable
|
||||
{
|
||||
return ![self submenu] || [self action] !== @selector(submenuAction:) || [self target] !== [self menu];
|
||||
}
|
||||
|
||||
- (BOOL)_isMenuBarButton
|
||||
{
|
||||
return ![self submenu] && [self menu] === [CPApp mainMenu];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
||||
var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
||||
|
||||
CPMenuItemTitleKey = @"CPMenuItemTitleKey",
|
||||
CPMenuItemTargetKey = @"CPMenuItemTargetKey",
|
||||
CPMenuItemActionKey = @"CPMenuItemActionKey",
|
||||
CPMenuItemTitleKey = @"CPMenuItemTitleKey",
|
||||
CPMenuItemTargetKey = @"CPMenuItemTargetKey",
|
||||
CPMenuItemActionKey = @"CPMenuItemActionKey",
|
||||
|
||||
CPMenuItemIsEnabledKey = @"CPMenuItemIsEnabledKey",
|
||||
CPMenuItemIsHiddenKey = @"CPMenuItemIsHiddenKey",
|
||||
CPMenuItemIsEnabledKey = @"CPMenuItemIsEnabledKey",
|
||||
CPMenuItemIsHiddenKey = @"CPMenuItemIsHiddenKey",
|
||||
|
||||
CPMenuItemTagKey = @"CPMenuItemTagKey",
|
||||
CPMenuItemStateKey = @"CPMenuItemStateKey",
|
||||
CPMenuItemTagKey = @"CPMenuItemTagKey",
|
||||
CPMenuItemStateKey = @"CPMenuItemStateKey",
|
||||
|
||||
CPMenuItemImageKey = @"CPMenuItemImageKey",
|
||||
CPMenuItemAlternateImageKey = @"CPMenuItemAlternateImageKey",
|
||||
CPMenuItemImageKey = @"CPMenuItemImageKey",
|
||||
CPMenuItemAlternateImageKey = @"CPMenuItemAlternateImageKey",
|
||||
|
||||
CPMenuItemSubmenuKey = @"CPMenuItemSubmenuKey",
|
||||
CPMenuItemMenuKey = @"CPMenuItemMenuKey",
|
||||
CPMenuItemSubmenuKey = @"CPMenuItemSubmenuKey",
|
||||
CPMenuItemMenuKey = @"CPMenuItemMenuKey",
|
||||
|
||||
CPMenuItemRepresentedObjectKey = @"CPMenuItemRepresentedObjectKey",
|
||||
CPMenuItemViewKey = @"CPMenuItemViewKey";
|
||||
CPMenuItemKeyEquivalentKey = @"CPMenuItemKeyEquivalentKey",
|
||||
CPMenuItemKeyEquivalentModifierMaskKey = @"CPMenuItemKeyEquivalentModifierMaskKey",
|
||||
|
||||
CPMenuItemIndentationLevelKey = @"CPMenuItemIndentationLevelKey",
|
||||
|
||||
CPMenuItemRepresentedObjectKey = @"CPMenuItemRepresentedObjectKey",
|
||||
CPMenuItemViewKey = @"CPMenuItemViewKey";
|
||||
|
||||
#define DEFAULT_VALUE(aKey, aDefaultValue) [aCoder containsValueForKey:(aKey)] ? [aCoder decodeObjectForKey:(aKey)] : (aDefaultValue)
|
||||
#define ENCODE_IFNOT(aKey, aValue, aDefaultValue) if ((aValue) !== (aDefaultValue)) [aCoder encodeObject:(aValue) forKey:(aKey)];
|
||||
@@ -796,16 +868,19 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
||||
// CPImage _offStateImage;
|
||||
// CPImage _mixedStateImage;
|
||||
|
||||
_submenu = DEFAULT_VALUE(CPMenuItemSubmenuKey, nil);
|
||||
// This order matters because setSubmenu: needs _menu to be around.
|
||||
_menu = DEFAULT_VALUE(CPMenuItemMenuKey, nil);
|
||||
[self setSubmenu:DEFAULT_VALUE(CPMenuItemSubmenuKey, nil)];
|
||||
|
||||
// CPString _keyEquivalent;
|
||||
// unsigned _keyEquivalentModifierMask;
|
||||
_keyEquivalent = [aCoder decodeObjectForKey:CPMenuItemKeyEquivalentKey] || @"";
|
||||
_keyEquivalentModifierMask = [aCoder decodeObjectForKey:CPMenuItemKeyEquivalentModifierMaskKey] || 0;
|
||||
|
||||
// int _mnemonicLocation;
|
||||
|
||||
// BOOL _isAlternate;
|
||||
// int _indentationLevel;
|
||||
|
||||
// Default is 0.
|
||||
[self setIndentationLevel:[aCoder decodeIntForKey:CPMenuItemIndentationLevelKey] || 0];
|
||||
|
||||
// CPString _toolTip;
|
||||
|
||||
@@ -842,423 +917,17 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
||||
ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil);
|
||||
ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil);
|
||||
|
||||
if (_keyEquivalent && _keyEquivalent.length)
|
||||
[aCoder encodeObject:_keyEquivalent forKey:CPMenuItemKeyEquivalentKey];
|
||||
|
||||
if (_keyEquivalentModifierMask)
|
||||
[aCoder encodeObject:_keyEquivalentModifierMask forKey:CPMenuItemKeyEquivalentModifierMaskKey];
|
||||
|
||||
if (_indentationLevel > 0)
|
||||
[aCoder encodeInt:_indentationLevel forKey:CPMenuItemIndentationLevelKey];
|
||||
|
||||
ENCODE_IFNOT(CPMenuItemRepresentedObjectKey, _representedObject, nil);
|
||||
ENCODE_IFNOT(CPMenuItemViewKey, _view, nil);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var LEFT_MARGIN = 3.0,
|
||||
RIGHT_MARGIN = 16.0,
|
||||
STATE_COLUMN_WIDTH = 14.0,
|
||||
INDENTATION_WIDTH = 17.0,
|
||||
VERTICAL_MARGIN = 4.0;
|
||||
|
||||
var _CPMenuItemSelectionColor = nil,
|
||||
_CPMenuItemTextShadowColor = nil,
|
||||
|
||||
_CPMenuItemDefaultStateImages = [],
|
||||
_CPMenuItemDefaultStateHighlightedImages = [];
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
@implementation _CPMenuItemView : CPView
|
||||
{
|
||||
CPMenuItem _menuItem;
|
||||
|
||||
CPFont _font;
|
||||
CPColor _textColor;
|
||||
CPColor _textShadowColor;
|
||||
CPColor _activateColor;
|
||||
CPColor _activateShadowColor;
|
||||
|
||||
CGSize _minSize;
|
||||
BOOL _isDirty;
|
||||
BOOL _showsStateColumn;
|
||||
BOOL _belongsToMenuBar;
|
||||
|
||||
CPImageView _stateView;
|
||||
_CPImageAndTextView _imageAndTextView;
|
||||
CPView _submenuView;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self != [_CPMenuItemView class])
|
||||
return;
|
||||
|
||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPOffState] = nil;
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
|
||||
}
|
||||
|
||||
+ (float)leftMargin
|
||||
{
|
||||
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame forMenuItem:(CPMenuItem)aMenuItem
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_menuItem = aMenuItem;
|
||||
_showsStateColumn = YES;
|
||||
_isDirty = YES;
|
||||
|
||||
[self setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
[self synchronizeWithMenuItem];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGSize)minSize
|
||||
{
|
||||
return _minSize;
|
||||
}
|
||||
|
||||
- (void)setDirty
|
||||
{
|
||||
_isDirty = YES;
|
||||
}
|
||||
|
||||
- (void)synchronizeWithMenuItem
|
||||
{
|
||||
if (!_isDirty)
|
||||
return;
|
||||
|
||||
_isDirty = NO;
|
||||
|
||||
var view = [_menuItem view];
|
||||
|
||||
if ([_menuItem isSeparatorItem])
|
||||
{
|
||||
var line = [[CPView alloc] initWithFrame:CGRectMake(0.0, 5.0, 10.0, 1.0)];
|
||||
|
||||
view = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 10.0)];
|
||||
|
||||
[view setAutoresizingMask:CPViewWidthSizable];
|
||||
[line setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
[line setBackgroundColor:[CPColor lightGrayColor]];
|
||||
|
||||
[view addSubview:line];
|
||||
}
|
||||
|
||||
if (view)
|
||||
{
|
||||
[_imageAndTextView removeFromSuperview];
|
||||
_imageAndTextView = nil;
|
||||
|
||||
[_stateView removeFromSuperview];
|
||||
_stateView = nil;
|
||||
|
||||
[_submenuView removeFromSuperview];
|
||||
_submenuView = nil;
|
||||
|
||||
_minSize = [view frame].size;
|
||||
|
||||
[self setFrameSize:_minSize];
|
||||
|
||||
[self addSubview:view];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// State Column
|
||||
var x = _belongsToMenuBar ? 0.0 : (LEFT_MARGIN + [_menuItem indentationLevel] * INDENTATION_WIDTH);
|
||||
|
||||
if (_showsStateColumn)
|
||||
{
|
||||
if (!_stateView)
|
||||
{
|
||||
_stateView = [[CPImageView alloc] initWithFrame:CGRectMake(x, (CGRectGetHeight([self frame]) - STATE_COLUMN_WIDTH) / 2.0, STATE_COLUMN_WIDTH, STATE_COLUMN_WIDTH)];
|
||||
|
||||
[_stateView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
|
||||
|
||||
[self addSubview:_stateView];
|
||||
}
|
||||
|
||||
var state = [_menuItem state];
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case CPOffState:
|
||||
case CPOnState:
|
||||
case CPMixedState: [_stateView setImage:_CPMenuItemDefaultStateImages[state]];
|
||||
break;
|
||||
|
||||
default: [_stateView setImage:nil];
|
||||
}
|
||||
|
||||
x += STATE_COLUMN_WIDTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
[_stateView removeFromSuperview];
|
||||
|
||||
_stateView = nil;
|
||||
}
|
||||
|
||||
// Image and Title
|
||||
|
||||
if (!_imageAndTextView)
|
||||
{
|
||||
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
|
||||
|
||||
[_imageAndTextView setImagePosition:CPImageLeft];
|
||||
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||
|
||||
[self addSubview:_imageAndTextView];
|
||||
}
|
||||
|
||||
var font = [_menuItem font];
|
||||
|
||||
if (!font)
|
||||
font = _font;
|
||||
|
||||
[_imageAndTextView setFont:font];
|
||||
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||
[_imageAndTextView setImage:[_menuItem image]];
|
||||
[_imageAndTextView setText:[_menuItem title]];
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
[_imageAndTextView setTextShadowOffset:CGSizeMake(0, 1)];
|
||||
[_imageAndTextView setFrameOrigin:CGPointMake(x, VERTICAL_MARGIN)];
|
||||
[_imageAndTextView sizeToFit];
|
||||
|
||||
var frame = [_imageAndTextView frame];
|
||||
|
||||
// frame.size.height += 1.0;
|
||||
// [_imageAndTextView setFrame:frame];
|
||||
|
||||
frame.size.height += 2 * VERTICAL_MARGIN;
|
||||
|
||||
x += CGRectGetWidth(frame);
|
||||
|
||||
// Submenu Arrow
|
||||
if ([_menuItem hasSubmenu])
|
||||
{
|
||||
x += 3.0;
|
||||
|
||||
if (!_submenuView)
|
||||
{
|
||||
_submenuView = [[_CPMenuItemArrowView alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)];
|
||||
|
||||
[self addSubview:_submenuView];
|
||||
}
|
||||
|
||||
[_submenuView setHidden:NO];
|
||||
[_submenuView setColor:_belongsToMenuBar ? [self textColor] : nil];
|
||||
[_submenuView setFrameOrigin:CGPointMake(x, (CGRectGetHeight(frame) - 10.0) / 2.0)];
|
||||
|
||||
x += 10.0;
|
||||
}
|
||||
else
|
||||
[_submenuView setHidden:YES];
|
||||
|
||||
_minSize = CGSizeMake(x + (_belongsToMenuBar ? 0.0 : RIGHT_MARGIN) + 3.0, CGRectGetHeight(frame));
|
||||
|
||||
[self setFrameSize:_minSize];
|
||||
}
|
||||
|
||||
- (CGFloat)overlapOffsetWidth
|
||||
{
|
||||
return LEFT_MARGIN + ([[_menuItem menu] showsStateColumn] ? STATE_COLUMN_WIDTH : 0.0);
|
||||
}
|
||||
|
||||
- (void)setShowsStateColumn:(BOOL)shouldShowStateColumn
|
||||
{
|
||||
_showsStateColumn = shouldShowStateColumn;
|
||||
}
|
||||
|
||||
- (void)setBelongsToMenuBar:(BOOL)shouldBelongToMenuBar
|
||||
{
|
||||
_belongsToMenuBar = shouldBelongToMenuBar;
|
||||
}
|
||||
|
||||
- (void)highlight:(BOOL)shouldHighlight
|
||||
{
|
||||
// ASSERT(![_menuItem view]);
|
||||
|
||||
if (_belongsToMenuBar)
|
||||
[_imageAndTextView setImage:shouldHighlight ? [_menuItem alternateImage] : [_menuItem image]];
|
||||
|
||||
else if ([_menuItem isEnabled])
|
||||
{
|
||||
if (shouldHighlight)
|
||||
{
|
||||
[self setBackgroundColor:_CPMenuItemSelectionColor];
|
||||
|
||||
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
||||
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setBackgroundColor:nil];
|
||||
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
}
|
||||
|
||||
var state = [_menuItem state];
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case CPOffState:
|
||||
case CPOnState:
|
||||
case CPMixedState: [_stateView setImage:shouldHighlight ? _CPMenuItemDefaultStateHighlightedImages[state] : _CPMenuItemDefaultStateImages[state]];
|
||||
break;
|
||||
|
||||
default: [_stateView setImage:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)activate:(BOOL)shouldActivate
|
||||
{
|
||||
[_imageAndTextView setImage:[_menuItem image]];
|
||||
|
||||
if (shouldActivate)
|
||||
{
|
||||
[_imageAndTextView setTextColor:[self activateColor] || [CPColor whiteColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self activateShadowColor] || [CPColor blackColor]];
|
||||
[_submenuView setColor:[self activateColor] || [CPColor whiteColor]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
[_submenuView setColor:[self textColor]];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)eventOnSubmenu:(CPEvent)anEvent
|
||||
{
|
||||
if (![_menuItem hasSubmenu])
|
||||
return NO;
|
||||
|
||||
return CGRectContainsPoint([_submenuView frame], [self convertPoint:[anEvent locationInWindow] fromView:nil]);
|
||||
}
|
||||
|
||||
- (BOOL)isHidden
|
||||
{
|
||||
return [_menuItem isHidden];
|
||||
}
|
||||
|
||||
- (CPMenuItem)menuItem
|
||||
{
|
||||
return _menuItem;
|
||||
}
|
||||
|
||||
- (void)setFont:(CPFont)aFont
|
||||
{
|
||||
if (_font == aFont)
|
||||
return;
|
||||
|
||||
_font = aFont;
|
||||
|
||||
[self setDirty];
|
||||
}
|
||||
|
||||
- (void)setTextColor:(CPColor)aColor
|
||||
{
|
||||
if (_textColor == aColor)
|
||||
return;
|
||||
|
||||
_textColor = aColor;
|
||||
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_submenuView setColor:[self textColor]];
|
||||
}
|
||||
|
||||
- (CPColor)textColor
|
||||
{
|
||||
return [_menuItem isEnabled] ? (_textColor ? _textColor : [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0]) : [CPColor lightGrayColor];
|
||||
}
|
||||
|
||||
- (void)setTextShadowColor:(CPColor)aColor
|
||||
{
|
||||
if (_textShadowColor == aColor)
|
||||
return;
|
||||
|
||||
_textShadowColor = aColor;
|
||||
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
//[_submenuView setColor:[self textColor]];
|
||||
}
|
||||
|
||||
- (CPColor)textShadowColor
|
||||
{
|
||||
return [_menuItem isEnabled] ? (_textShadowColor ? _textShadowColor : [CPColor colorWithWhite:1.0 alpha:0.8]) : [CPColor colorWithWhite:0.8 alpha:0.8];
|
||||
}
|
||||
|
||||
- (void)setActivateColor:(CPColor)aColor
|
||||
{
|
||||
_activateColor = aColor;
|
||||
}
|
||||
|
||||
- (CPColor)activateColor
|
||||
{
|
||||
return _activateColor;
|
||||
}
|
||||
|
||||
- (void)setActivateShadowColor:(CPColor)aColor
|
||||
{
|
||||
_activateShadowColor = aColor;
|
||||
}
|
||||
|
||||
- (CPColor)activateShadowColor
|
||||
{
|
||||
return _activateShadowColor;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPMenuItemArrowView : CPView
|
||||
{
|
||||
CPColor _color;
|
||||
}
|
||||
|
||||
- (void)setColor:(CPColor)aColor
|
||||
{
|
||||
if (_color == aColor)
|
||||
return;
|
||||
|
||||
_color = aColor;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGContextBeginPath(context);
|
||||
|
||||
CGContextMoveToPoint(context, 1.0, 4.0);
|
||||
CGContextAddLineToPoint(context, 9.0, 4.0);
|
||||
CGContextAddLineToPoint(context, 5.0, 8.0);
|
||||
CGContextAddLineToPoint(context, 1.0, 4.0);
|
||||
|
||||
CGContextClosePath(context);
|
||||
|
||||
CGContextSetFillColor(context, _color);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,235 @@
|
||||
var HORIZONTAL_MARGIN = 8.0,
|
||||
SUBMENU_INDICATOR_MARGIN = 3.0,
|
||||
VERTICAL_MARGIN = 4.0;
|
||||
|
||||
var SelectionColor = nil,
|
||||
SUBMENU_INDICATOR_COLOR = nil,
|
||||
_CPMenuItemSelectionColor = nil,
|
||||
_CPMenuItemTextShadowColor = nil,
|
||||
|
||||
_CPMenuItemDefaultStateImages = [],
|
||||
_CPMenuItemDefaultStateHighlightedImages = [];
|
||||
|
||||
@implementation _CPMenuItemMenuBarView : CPView
|
||||
{
|
||||
CPMenuItem _menuItem @accessors(property=menuItem);
|
||||
|
||||
CPFont _font;
|
||||
CPColor _textColor;
|
||||
CPColor _textShadowColor;
|
||||
|
||||
BOOL _isDirty;
|
||||
|
||||
_CPImageAndTextView _imageAndTextView;
|
||||
CPView _submenuIndicatorView;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self !== [_CPMenuItemMenuBarView class])
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
SelectionColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuBarWindow/_CPMenuBarWindowBackgroundSelected.png"] size:CGSizeMake(1.0, 28.0)]];
|
||||
|
||||
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
|
||||
|
||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPOffState] = nil;
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
|
||||
}
|
||||
|
||||
+ (id)view
|
||||
{
|
||||
return [[self alloc] init];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(HORIZONTAL_MARGIN, 0.0, 0.0, 0.0)];
|
||||
|
||||
[_imageAndTextView setImagePosition:CPImageLeft];
|
||||
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||
[_imageAndTextView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
|
||||
|
||||
[self addSubview:_imageAndTextView];
|
||||
|
||||
_submenuIndicatorView = [[_CPMenuItemMenuBarSubmenuIndicatorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 9.0, 6.0)];
|
||||
|
||||
[_submenuIndicatorView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
|
||||
|
||||
[self addSubview:_submenuIndicatorView];
|
||||
|
||||
[self setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPColor)textColor
|
||||
{
|
||||
if (![_menuItem isEnabled])
|
||||
return [CPColor lightGrayColor];
|
||||
|
||||
return _textColor || [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0];
|
||||
}
|
||||
|
||||
- (CPColor)textShadowColor
|
||||
{
|
||||
if (![_menuItem isEnabled])
|
||||
return [CPColor colorWithWhite:0.8 alpha:0.8];
|
||||
|
||||
return _textShadowColor || [CPColor colorWithWhite:1.0 alpha:0.8];
|
||||
}
|
||||
|
||||
- (void)update
|
||||
{
|
||||
var x = HORIZONTAL_MARGIN,
|
||||
height = 0.0;
|
||||
|
||||
[_imageAndTextView setFont:[_menuItem font] || [_CPMenuBarWindow font]];
|
||||
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||
[_imageAndTextView setImage:[_menuItem image]];
|
||||
[_imageAndTextView setText:[_menuItem title]];
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||
[_imageAndTextView sizeToFit];
|
||||
|
||||
var imageAndTextViewFrame = [_imageAndTextView frame];
|
||||
|
||||
imageAndTextViewFrame.origin.x = x;
|
||||
x += CGRectGetWidth(imageAndTextViewFrame);
|
||||
height = MAX(height, CGRectGetHeight(imageAndTextViewFrame));
|
||||
|
||||
var hasSubmenuIndicator = [_menuItem hasSubmenu] && [_menuItem action];
|
||||
|
||||
if (hasSubmenuIndicator)
|
||||
{
|
||||
[_submenuIndicatorView setHidden:NO];
|
||||
[_submenuIndicatorView setColor:[self textColor]];
|
||||
[_submenuIndicatorView setShadowColor:[self textShadowColor]];
|
||||
|
||||
var submenuViewFrame = [_submenuIndicatorView frame];
|
||||
|
||||
submenuViewFrame.origin.x = x + SUBMENU_INDICATOR_MARGIN;
|
||||
|
||||
x = CGRectGetMaxX(submenuViewFrame);
|
||||
height = MAX(height, CGRectGetHeight(submenuViewFrame));
|
||||
}
|
||||
else
|
||||
[_submenuIndicatorView setHidden:YES];
|
||||
|
||||
height += 2.0 * VERTICAL_MARGIN;
|
||||
|
||||
imageAndTextViewFrame.origin.y = FLOOR((height - CGRectGetHeight(imageAndTextViewFrame)) / 2.0);
|
||||
[_imageAndTextView setFrame:imageAndTextViewFrame];
|
||||
|
||||
if (hasSubmenuIndicator)
|
||||
{
|
||||
submenuViewFrame.origin.y = FLOOR((height - CGRectGetHeight(submenuViewFrame)) / 2.0) + 1.0;
|
||||
[_submenuIndicatorView setFrame:submenuViewFrame];
|
||||
}
|
||||
|
||||
_minSize = CGSizeMake(x + HORIZONTAL_MARGIN, height);
|
||||
|
||||
[self setAutoresizesSubviews:NO];
|
||||
[self setFrameSize:_minSize];
|
||||
[self setAutoresizesSubviews:YES];
|
||||
}
|
||||
|
||||
- (void)highlight:(BOOL)shouldHighlight
|
||||
{
|
||||
// FIXME: This should probably be even throw.
|
||||
if (![_menuItem isEnabled])
|
||||
shouldHighlight = NO;
|
||||
|
||||
if (shouldHighlight)
|
||||
{
|
||||
if (![_menuItem _isMenuBarButton])
|
||||
[self setBackgroundColor:SelectionColor];
|
||||
|
||||
[_imageAndTextView setImage:[_menuItem alternateImage] || [_menuItem image]];
|
||||
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
||||
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
|
||||
|
||||
[_submenuIndicatorView setColor:[CPColor whiteColor]];
|
||||
[_submenuIndicatorView setShadowColor:[CPColor colorWithWhite:0.1 alpha:0.7]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setBackgroundColor:nil];
|
||||
|
||||
[_imageAndTextView setImage:[_menuItem image]];
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
|
||||
[_submenuIndicatorView setColor:[self textColor]];
|
||||
[_submenuIndicatorView setShadowColor:[self textShadowColor]];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPMenuItemMenuBarSubmenuIndicatorView : CPView
|
||||
{
|
||||
CPColor _color;
|
||||
CPColor _shadowColor;
|
||||
}
|
||||
|
||||
- (void)setColor:(CPColor)aColor
|
||||
{
|
||||
if (_color === aColor)
|
||||
return;
|
||||
|
||||
_color = aColor;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)setShadowColor:(CPColor)aColor
|
||||
{
|
||||
if (_shadowColor === aColor)
|
||||
return;
|
||||
|
||||
_shadowColor = aColor;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
bounds = [self bounds];
|
||||
|
||||
bounds.size.height -= 1.0;
|
||||
bounds.size.width -= 2.0;
|
||||
bounds.origin.x += 1.0;
|
||||
|
||||
CGContextBeginPath(context);
|
||||
|
||||
CGContextMoveToPoint(context, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
|
||||
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), CGRectGetMinY(bounds));
|
||||
CGContextAddLineToPoint(context, CGRectGetMidX(bounds), CGRectGetMaxY(bounds));
|
||||
|
||||
CGContextClosePath(context);
|
||||
|
||||
CGContextSetShadowWithColor(context, CGSizeMake(0.0, 1.0), 1.1, _shadowColor || [CPColor whiteColor]);
|
||||
CGContextSetFillColor(context, _color || [CPColor blackColor]);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
@import <AppKit/CPView.j>
|
||||
|
||||
|
||||
@implementation _CPMenuItemSeparatorView : CPView
|
||||
{
|
||||
}
|
||||
|
||||
+ (id)view
|
||||
{
|
||||
return [[self alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 10.0)];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
[self setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
bounds = [self bounds];
|
||||
|
||||
CGContextBeginPath(context);
|
||||
|
||||
CGContextMoveToPoint(context, CGRectGetMinX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
|
||||
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
|
||||
|
||||
CGContextSetStrokeColor(context, [CPColor lightGrayColor]);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,300 @@
|
||||
var LEFT_MARGIN = 3.0,
|
||||
RIGHT_MARGIN = 14.0 + 3.0,
|
||||
STATE_COLUMN_WIDTH = 14.0,
|
||||
INDENTATION_WIDTH = 17.0,
|
||||
VERTICAL_MARGIN = 4.0,
|
||||
|
||||
RIGHT_COLUMNS_MARGIN = 30.0,
|
||||
KEY_EQUIVALENT_MARGIN = 10.0;
|
||||
|
||||
var SUBMENU_INDICATOR_COLOR = nil,
|
||||
_CPMenuItemSelectionColor = nil,
|
||||
_CPMenuItemTextShadowColor = nil,
|
||||
|
||||
_CPMenuItemDefaultStateImages = [],
|
||||
_CPMenuItemDefaultStateHighlightedImages = [];
|
||||
|
||||
@implementation _CPMenuItemStandardView : CPView
|
||||
{
|
||||
CPMenuItem _menuItem @accessors(property=menuItem);
|
||||
|
||||
CPFont _font;
|
||||
CPColor _textColor;
|
||||
CPColor _textShadowColor;
|
||||
|
||||
CGSize _minSize @accessors(readonly, property=minSize);
|
||||
BOOL _isDirty;
|
||||
|
||||
CPImageView _stateView;
|
||||
_CPImageAndTextView _imageAndTextView;
|
||||
_CPImageAndTextView _keyEquivalentView;
|
||||
CPView _submenuIndicatorView;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self !== [_CPMenuItemStandardView class])
|
||||
return;
|
||||
|
||||
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
|
||||
|
||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPOffState] = nil;
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
|
||||
}
|
||||
|
||||
+ (id)view
|
||||
{
|
||||
return [[self alloc] init];
|
||||
}
|
||||
|
||||
+ (float)_standardLeftMargin
|
||||
{
|
||||
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_stateView = [[CPImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
|
||||
|
||||
[_stateView setImageScaling:CPScaleNone];
|
||||
|
||||
[self addSubview:_stateView];
|
||||
|
||||
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
|
||||
|
||||
[_imageAndTextView setImagePosition:CPImageLeft];
|
||||
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||
|
||||
[self addSubview:_imageAndTextView];
|
||||
|
||||
_keyEquivalentView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
|
||||
|
||||
[_keyEquivalentView setImagePosition:CPNoImage];
|
||||
[_keyEquivalentView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||
[_keyEquivalentView setAutoresizingMask:CPViewMinXMargin];
|
||||
|
||||
[self addSubview:_keyEquivalentView];
|
||||
|
||||
_submenuIndicatorView = [[_CPMenuItemSubmenuIndicatorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 8.0, 10.0)];
|
||||
|
||||
[_submenuIndicatorView setColor:SUBMENU_INDICATOR_COLOR];
|
||||
[_submenuIndicatorView setAutoresizingMask:CPViewMinXMargin];
|
||||
|
||||
[self addSubview:_submenuIndicatorView];
|
||||
|
||||
[self setAutoresizingMask:CPViewWidthSizable];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPColor)textColor
|
||||
{
|
||||
if (![_menuItem isEnabled])
|
||||
return [CPColor lightGrayColor];
|
||||
|
||||
return _textColor || [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0];
|
||||
}
|
||||
|
||||
- (CPColor)textShadowColor
|
||||
{
|
||||
if (![_menuItem isEnabled])
|
||||
return nil;
|
||||
|
||||
return _textShadowColor || [CPColor colorWithWhite:1.0 alpha:0.8];
|
||||
}
|
||||
|
||||
- (void)setFont:(CPFont)aFont
|
||||
{
|
||||
_font = aFont;
|
||||
}
|
||||
|
||||
- (void)update
|
||||
{
|
||||
var x = LEFT_MARGIN + [_menuItem indentationLevel] * INDENTATION_WIDTH,
|
||||
height = 0.0,
|
||||
hasStateColumn = [[_menuItem menu] showsStateColumn];
|
||||
|
||||
if (hasStateColumn)
|
||||
{
|
||||
[_stateView setHidden:NO];
|
||||
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
||||
|
||||
x += STATE_COLUMN_WIDTH;
|
||||
}
|
||||
else
|
||||
[_stateView setHidden:YES];
|
||||
|
||||
[_imageAndTextView setFont:[_menuItem font] || _font];
|
||||
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||
[_imageAndTextView setImage:[_menuItem image]];
|
||||
[_imageAndTextView setText:[_menuItem title]];
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||
[_imageAndTextView sizeToFit];
|
||||
|
||||
var imageAndTextViewFrame = [_imageAndTextView frame];
|
||||
|
||||
imageAndTextViewFrame.origin.x = x;
|
||||
x += CGRectGetWidth(imageAndTextViewFrame);
|
||||
height = MAX(height, CGRectGetHeight(imageAndTextViewFrame));
|
||||
|
||||
var hasKeyEquivalent = !![_menuItem keyEquivalent],
|
||||
hasSubmenu = [_menuItem hasSubmenu];
|
||||
|
||||
if (hasKeyEquivalent || hasSubmenu)
|
||||
x += RIGHT_COLUMNS_MARGIN;
|
||||
|
||||
if (hasKeyEquivalent)
|
||||
{
|
||||
[_keyEquivalentView setFont:[_menuItem font] || _font];
|
||||
[_keyEquivalentView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||
[_keyEquivalentView setImage:[_menuItem image]];
|
||||
[_keyEquivalentView setText:[_menuItem keyEquivalentStringRepresentation]];
|
||||
[_keyEquivalentView setTextColor:[self textColor]];
|
||||
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
||||
[_keyEquivalentView setTextShadowOffset:CGSizeMake(0, 1)];
|
||||
[_keyEquivalentView setFrameOrigin:CGPointMake(x, VERTICAL_MARGIN)];
|
||||
[_keyEquivalentView sizeToFit];
|
||||
|
||||
var keyEquivalentViewFrame = [_keyEquivalentView frame];
|
||||
|
||||
keyEquivalentViewFrame.origin.x = x;
|
||||
x += CGRectGetWidth(keyEquivalentViewFrame);
|
||||
height = MAX(height, CGRectGetHeight(keyEquivalentViewFrame));
|
||||
|
||||
if (hasSubmenu)
|
||||
x += RIGHT_COLUMNS_MARGIN;
|
||||
}
|
||||
else
|
||||
[_keyEquivalentView setHidden:YES];
|
||||
|
||||
if (hasSubmenu)
|
||||
{
|
||||
[_submenuIndicatorView setHidden:NO];
|
||||
|
||||
var submenuViewFrame = [_submenuIndicatorView frame];
|
||||
|
||||
submenuViewFrame.origin.x = x;
|
||||
|
||||
x += CGRectGetWidth(submenuViewFrame);
|
||||
height = MAX(height, CGRectGetHeight(submenuViewFrame));
|
||||
}
|
||||
else
|
||||
[_submenuIndicatorView setHidden:YES];
|
||||
|
||||
height += 2.0 * VERTICAL_MARGIN;
|
||||
|
||||
imageAndTextViewFrame.origin.y = FLOOR((height - CGRectGetHeight(imageAndTextViewFrame)) / 2.0);
|
||||
[_imageAndTextView setFrame:imageAndTextViewFrame];
|
||||
|
||||
if (hasStateColumn)
|
||||
[_stateView setFrameSize:CGSizeMake(STATE_COLUMN_WIDTH, height)];
|
||||
|
||||
if (hasKeyEquivalent)
|
||||
{
|
||||
keyEquivalentViewFrame.origin.y = FLOOR((height - CGRectGetHeight(keyEquivalentViewFrame)) / 2.0);
|
||||
[_keyEquivalentView setFrame:keyEquivalentViewFrame];
|
||||
}
|
||||
|
||||
if (hasSubmenu)
|
||||
{
|
||||
submenuViewFrame.origin.y = FLOOR((height - CGRectGetHeight(submenuViewFrame)) / 2.0);
|
||||
[_submenuIndicatorView setFrame:submenuViewFrame];
|
||||
}
|
||||
|
||||
_minSize = CGSizeMake(x + RIGHT_MARGIN, height);
|
||||
|
||||
[self setAutoresizesSubviews:NO];
|
||||
[self setFrameSize:_minSize];
|
||||
[self setAutoresizesSubviews:YES];
|
||||
}
|
||||
|
||||
- (void)highlight:(BOOL)shouldHighlight
|
||||
{
|
||||
// FIXME: This should probably be even throw.
|
||||
if (![_menuItem isEnabled])
|
||||
return;
|
||||
|
||||
if (shouldHighlight)
|
||||
{
|
||||
[self setBackgroundColor:_CPMenuItemSelectionColor];
|
||||
|
||||
[_imageAndTextView setImage:[_menuItem alternateImage] || [_menuItem image]];
|
||||
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
||||
[_keyEquivalentView setTextColor:[CPColor whiteColor]];
|
||||
[_submenuIndicatorView setColor:[CPColor whiteColor]];
|
||||
|
||||
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
|
||||
[_keyEquivalentView setTextShadowColor:_CPMenuItemTextShadowColor];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setBackgroundColor:nil];
|
||||
|
||||
[_imageAndTextView setImage:[_menuItem image]];
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_keyEquivalentView setTextColor:[self textColor]];
|
||||
[_submenuIndicatorView setColor:SUBMENU_INDICATOR_COLOR];
|
||||
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
||||
}
|
||||
|
||||
if (shouldHighlight)
|
||||
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
|
||||
else
|
||||
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPMenuItemSubmenuIndicatorView : CPView
|
||||
{
|
||||
CPColor _color;
|
||||
}
|
||||
|
||||
- (void)setColor:(CPColor)aColor
|
||||
{
|
||||
if (_color === aColor)
|
||||
return;
|
||||
|
||||
_color = aColor;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
bounds = [self bounds];
|
||||
|
||||
CGContextBeginPath(context);
|
||||
|
||||
CGContextMoveToPoint(context, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
|
||||
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), CGRectGetMidY(bounds));
|
||||
CGContextAddLineToPoint(context, CGRectGetMinX(bounds), CGRectGetMaxY(bounds));
|
||||
|
||||
CGContextClosePath(context);
|
||||
|
||||
CGContextSetFillColor(context, _color);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,255 @@
|
||||
|
||||
@import "_CPMenuItemSeparatorView.j"
|
||||
@import "_CPMenuItemStandardView.j"
|
||||
@import "_CPMenuItemMenuBarView.j"
|
||||
|
||||
|
||||
var LEFT_MARGIN = 3.0,
|
||||
RIGHT_MARGIN = 16.0,
|
||||
STATE_COLUMN_WIDTH = 14.0,
|
||||
INDENTATION_WIDTH = 17.0,
|
||||
VERTICAL_MARGIN = 4.0;
|
||||
|
||||
var _CPMenuItemSelectionColor = nil,
|
||||
_CPMenuItemTextShadowColor = nil,
|
||||
|
||||
_CPMenuItemDefaultStateImages = [],
|
||||
_CPMenuItemDefaultStateHighlightedImages = [];
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
@implementation _CPMenuItemView : CPView
|
||||
{
|
||||
CPMenuItem _menuItem;
|
||||
CPView _view;
|
||||
|
||||
CPFont _font;
|
||||
CPColor _textColor;
|
||||
CPColor _textShadowColor;
|
||||
|
||||
CGSize _minSize;
|
||||
BOOL _isDirty;
|
||||
BOOL _showsStateColumn;
|
||||
|
||||
CPImageView _stateView;
|
||||
_CPImageAndTextView _imageAndTextView;
|
||||
CPView _submenuView;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self != [_CPMenuItemView class])
|
||||
return;
|
||||
|
||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPOffState] = nil;
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
|
||||
|
||||
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
|
||||
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
|
||||
}
|
||||
|
||||
+ (float)leftMargin
|
||||
{
|
||||
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame forMenuItem:(CPMenuItem)aMenuItem
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_menuItem = aMenuItem;
|
||||
_showsStateColumn = YES;
|
||||
_isDirty = YES;
|
||||
|
||||
[self setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
[self synchronizeWithMenuItem];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGSize)minSize
|
||||
{
|
||||
return _minSize;
|
||||
}
|
||||
|
||||
- (void)setDirty
|
||||
{
|
||||
_isDirty = YES;
|
||||
}
|
||||
|
||||
- (void)synchronizeWithMenuItem
|
||||
{
|
||||
var menuItemView = [_menuItem view];
|
||||
|
||||
if ([_menuItem isSeparatorItem])
|
||||
{
|
||||
if (![_view isKindOfClass:[_CPMenuItemSeparatorView class]])
|
||||
{
|
||||
[_view removeFromSuperview];
|
||||
_view = [_CPMenuItemSeparatorView view];
|
||||
}
|
||||
}
|
||||
else if (menuItemView)
|
||||
{
|
||||
if (_view !== menuItemView)
|
||||
{
|
||||
[_view removeFromSuperview];
|
||||
_view = menuItemView;
|
||||
}
|
||||
}
|
||||
|
||||
else if ([_menuItem menu] == [CPApp mainMenu])
|
||||
{
|
||||
if (![_view isKindOfClass:[_CPMenuItemMenuBarView class]])
|
||||
{
|
||||
[_view removeFromSuperview];
|
||||
_view = [_CPMenuItemMenuBarView view];
|
||||
}
|
||||
|
||||
[_view setMenuItem:_menuItem];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (![_view isKindOfClass:[_CPMenuItemStandardView class]])
|
||||
{
|
||||
[_view removeFromSuperview];
|
||||
_view = [_CPMenuItemStandardView view];
|
||||
}
|
||||
|
||||
[_view setMenuItem:_menuItem];
|
||||
}
|
||||
|
||||
if ([_view superview] !== self)
|
||||
[self addSubview:_view];
|
||||
|
||||
if ([_view respondsToSelector:@selector(update)])
|
||||
[_view update];
|
||||
|
||||
_minSize = [_view frame].size;
|
||||
[self setAutoresizesSubviews:NO];
|
||||
[self setFrameSize:_minSize];
|
||||
[self setAutoresizesSubviews:YES];
|
||||
}
|
||||
|
||||
- (void)setShowsStateColumn:(BOOL)shouldShowStateColumn
|
||||
{
|
||||
_showsStateColumn = shouldShowStateColumn;
|
||||
}
|
||||
|
||||
- (void)highlight:(BOOL)shouldHighlight
|
||||
{
|
||||
if ([_view respondsToSelector:@selector(highlight:)])
|
||||
[_view highlight:shouldHighlight];
|
||||
}
|
||||
|
||||
- (BOOL)eventOnSubmenu:(CPEvent)anEvent
|
||||
{
|
||||
if (![_menuItem hasSubmenu])
|
||||
return NO;
|
||||
|
||||
return CGRectContainsPoint([_submenuView frame], [self convertPoint:[anEvent locationInWindow] fromView:nil]);
|
||||
}
|
||||
|
||||
- (BOOL)isHidden
|
||||
{
|
||||
return [_menuItem isHidden];
|
||||
}
|
||||
|
||||
- (CPMenuItem)menuItem
|
||||
{
|
||||
return _menuItem;
|
||||
}
|
||||
|
||||
- (void)setFont:(CPFont)aFont
|
||||
{
|
||||
if (_font === aFont)
|
||||
return;
|
||||
|
||||
_font = aFont;
|
||||
|
||||
if ([_view respondsToSelector:@selector(setFont:)])
|
||||
[_view setFont:aFont];
|
||||
|
||||
[self setDirty];
|
||||
}
|
||||
|
||||
- (void)setTextColor:(CPColor)aColor
|
||||
{
|
||||
if (_textColor == aColor)
|
||||
return;
|
||||
|
||||
_textColor = aColor;
|
||||
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_submenuView setColor:[self textColor]];
|
||||
}
|
||||
|
||||
- (CPColor)textColor
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setTextShadowColor:(CPColor)aColor
|
||||
{
|
||||
if (_textShadowColor == aColor)
|
||||
return;
|
||||
|
||||
_textShadowColor = aColor;
|
||||
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
//[_submenuView setColor:[self textColor]];
|
||||
}
|
||||
|
||||
- (CPColor)textShadowColor
|
||||
{
|
||||
return [_menuItem isEnabled] ? (_textShadowColor ? _textShadowColor : [CPColor colorWithWhite:1.0 alpha:0.8]) : [CPColor colorWithWhite:0.8 alpha:0.8];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPMenuItemArrowView : CPView
|
||||
{
|
||||
CPColor _color;
|
||||
}
|
||||
|
||||
- (void)setColor:(CPColor)aColor
|
||||
{
|
||||
if (_color == aColor)
|
||||
return;
|
||||
|
||||
_color = aColor;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGContextBeginPath(context);
|
||||
|
||||
CGContextMoveToPoint(context, 1.0, 4.0);
|
||||
CGContextAddLineToPoint(context, 9.0, 4.0);
|
||||
CGContextAddLineToPoint(context, 5.0, 8.0);
|
||||
CGContextAddLineToPoint(context, 1.0, 4.0);
|
||||
|
||||
CGContextClosePath(context);
|
||||
|
||||
CGContextSetFillColor(context, _color);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
@end
|
||||
+24
-39
@@ -1,61 +1,46 @@
|
||||
|
||||
@import <AppKit/CPPanel.j>
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
var SharedOpenPanel = nil;
|
||||
|
||||
@implementation CPOpenPanel : CPPanel
|
||||
{
|
||||
CPArray _files;
|
||||
BOOL _canChooseFiles @accessors(property=canChooseFiles);
|
||||
BOOL _canChooseDirectories @accessors(property=canChooseDirectories);
|
||||
BOOL _allowsMultipleSelection @accessors(property=allowsMultipleSelection);
|
||||
BOOL _canChooseFiles @accessors(property=canChooseFiles);
|
||||
BOOL _canChooseDirectories @accessors(property=canChooseDirectories);
|
||||
BOOL _allowsMultipleSelection @accessors(property=allowsMultipleSelection);
|
||||
CPURL _directoryURL @accessors(property=directoryURL);
|
||||
CPArray _URLs;
|
||||
}
|
||||
|
||||
+ (id)openPanel
|
||||
{
|
||||
if (!SharedOpenPanel)
|
||||
SharedOpenPanel = [[CPOpenPanel alloc] init];
|
||||
|
||||
return SharedOpenPanel;
|
||||
return [[CPOpenPanel alloc] init];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
- (CPInteger)runModal
|
||||
{
|
||||
if (self = [super init])
|
||||
if (typeof window["cpOpenPanel"] === "function")
|
||||
{
|
||||
_files = [];
|
||||
_canChooseFiles = YES;
|
||||
// FIXME: Is this correct???
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
|
||||
var options = { directoryURL: [self directoryURL],
|
||||
canChooseFiles: [self canChooseFiles],
|
||||
canChooseDirectories: [self canChooseDirectories],
|
||||
allowsMultipleSelection: [self allowsMultipleSelection] };
|
||||
|
||||
var result = window.cpOpenPanel(options);
|
||||
|
||||
_URLs = result.URLs;
|
||||
|
||||
return result.button;
|
||||
}
|
||||
|
||||
return self;
|
||||
throw "-runModal is unimplemented.";
|
||||
}
|
||||
|
||||
- (void)filenames
|
||||
- (CPArray)URLs
|
||||
{
|
||||
return _files;
|
||||
}
|
||||
|
||||
- (unsigned)runModalForDirectory:(CPString)absoluteDirectoryPath file:(CPString)filename types:(CPArray)fileTypes
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
if (window.Titanium)
|
||||
{
|
||||
_files = Titanium.Desktop.openFiles({
|
||||
path:absoluteDirectoryPath,
|
||||
types:fileTypes,
|
||||
multiple:_allowsMultipleSelection,
|
||||
filename:filename,
|
||||
directories:_canChooseDirectories,
|
||||
files:_canChooseFiles
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (unsigned)runModalForTypes:(CPArray)fileTypes
|
||||
{alert("HERE");
|
||||
[self runModalForDirectory:"/" file:nil types:fileTypes];
|
||||
return _URLs;
|
||||
}
|
||||
|
||||
@end
|
||||
+413
-178
@@ -50,6 +50,15 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
||||
|
||||
CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_ = 1 << 10;
|
||||
|
||||
|
||||
var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ = 1 << 1,
|
||||
CPOutlineViewDelegate_outlineView_shouldSelectItem_ = 1 << 2,
|
||||
CPOutlineViewDelegate_outlineView_heightOfRowByItem_ = 1 << 3,
|
||||
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ = 1 << 4,
|
||||
CPOutlineViewDelegate_outlineView_isGroupItem_ = 1 << 5;
|
||||
|
||||
CPOutlineViewDropOnItemIndex = -1;
|
||||
|
||||
@implementation CPOutlineView : CPTableView
|
||||
{
|
||||
id _outlineViewDataSource;
|
||||
@@ -60,6 +69,7 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
||||
BOOL _indentationMarkerFollowsDataView;
|
||||
|
||||
CPInteger _implementedOutlineViewDataSourceMethods;
|
||||
CPInteger _implementedOutlineViewDelegateMethods;
|
||||
|
||||
Object _rootItemInfo;
|
||||
CPMutableArray _itemsForRows;
|
||||
@@ -69,6 +79,12 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
||||
CPArray _disclosureControlsForRows;
|
||||
CPData _disclosureControlData;
|
||||
CPArray _disclosureControlQueue;
|
||||
|
||||
BOOL _shouldRetargetItem;
|
||||
id _retargetedItem;
|
||||
|
||||
BOOL _shouldRetargetChildIndex;
|
||||
CPInteger _retargedChildIndex;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -77,6 +93,9 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
||||
|
||||
if (self)
|
||||
{
|
||||
|
||||
_selectionHighlightStyle = CPTableViewSelectionHighlightStyleSourceList;
|
||||
|
||||
// The root item has weight "0", thus represents the weight solely of its descendants.
|
||||
_rootItemInfo = { isExpanded:YES, isExpandable:NO, level:-1, row:-1, children:[], weight:0 };
|
||||
|
||||
@@ -84,10 +103,17 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
||||
_itemInfosForItems = { };
|
||||
_disclosureControlsForRows = [];
|
||||
|
||||
_retargetedItem = nil;
|
||||
_shouldRetargetItem = NO;
|
||||
|
||||
_retargedChildIndex = nil;
|
||||
_shouldRetargetChildIndex = NO;
|
||||
|
||||
[self setIndentationPerLevel:16.0];
|
||||
[self setIndentationMarkerFollowsDataView:YES];
|
||||
|
||||
[super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]];
|
||||
[super setDelegate:[[_CPOutlineViewTableViewDelegate alloc] initWithOutlineView:self]];
|
||||
|
||||
[self setDisclosureControlPrototype:[[CPDisclosureButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)]];
|
||||
}
|
||||
@@ -181,20 +207,32 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
||||
|
||||
- (void)expandItem:(id)anItem
|
||||
{
|
||||
if (!anItem)
|
||||
return;
|
||||
[self expandItem:anItem expandChildren:NO];
|
||||
}
|
||||
|
||||
var itemInfo = _itemInfosForItems[[anItem UID]];
|
||||
- (void)expandItem:(id)anItem expandChildren:(BOOL)shouldExpandChildren
|
||||
{
|
||||
var itemInfo = null;
|
||||
|
||||
if (!anItem)
|
||||
itemInfo = _rootItemInfo;
|
||||
else
|
||||
itemInfo = _itemInfosForItems[[anItem UID]];
|
||||
|
||||
if (!itemInfo)
|
||||
return;
|
||||
|
||||
if (itemInfo.isExpanded)
|
||||
return;
|
||||
|
||||
|
||||
itemInfo.isExpanded = YES;
|
||||
|
||||
[self reloadItem:anItem reloadChildren:YES];
|
||||
|
||||
if (shouldExpandChildren)
|
||||
{
|
||||
var children = itemInfo.children,
|
||||
childIndex = children.length;
|
||||
|
||||
while (childIndex--)
|
||||
[self expandItem:children[childIndex] expandChildren:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)collapseItem:(id)anItem
|
||||
@@ -235,7 +273,7 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
||||
return _itemsForRows[aRow] || nil;
|
||||
}
|
||||
|
||||
- (CPInteger)rowForItem:(id)aItem
|
||||
- (CPInteger)rowForItem:(id)anItem
|
||||
{
|
||||
if (!anItem)
|
||||
return _rootItemInfo.row;
|
||||
@@ -324,7 +362,13 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
||||
if (!itemInfo)
|
||||
return nil;
|
||||
|
||||
return itemInfo.parent;
|
||||
var parent = itemInfo.parent;
|
||||
|
||||
// Check if the parent is the root item because we never return the actual root item
|
||||
if (itemInfo[[parent UID]] === _rootItemInfo)
|
||||
parent = nil;
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
- (CGRect)frameOfOutlineDataViewAtColumn:(CPInteger)aColumn row:(CPInteger)aRow
|
||||
@@ -338,6 +382,45 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
||||
return frame;
|
||||
}
|
||||
|
||||
- (void)selectRowIndexes:(CPIndexSet)rows byExtendingSelection:(BOOL)shouldExtendSelection
|
||||
{
|
||||
// First un highlight the old disclosure controls
|
||||
var previousSelectedRows = [];
|
||||
[[self selectedRowIndexes] getIndexes:previousSelectedRows maxCount:-1 inIndexRange:nil];
|
||||
|
||||
var index = [previousSelectedRows count];
|
||||
while (index--)
|
||||
{
|
||||
var rowIndex = previousSelectedRows[index],
|
||||
item = [self itemAtRow:rowIndex];
|
||||
|
||||
if (![self isExpandable:item])
|
||||
continue;
|
||||
|
||||
var control = _disclosureControlsForRows[rowIndex];
|
||||
[control setHighlighted:NO];
|
||||
}
|
||||
|
||||
[super selectRowIndexes:rows byExtendingSelection:shouldExtendSelection];
|
||||
|
||||
// Now highlight the new disclosure controls
|
||||
var selectedRows = [];
|
||||
[rows getIndexes:selectedRows maxCount:-1 inIndexRange:nil];
|
||||
|
||||
var index = [selectedRows count];
|
||||
while (index--)
|
||||
{
|
||||
var rowIndex = selectedRows[index],
|
||||
item = [self itemAtRow:rowIndex];
|
||||
|
||||
if (![self isExpandable:item])
|
||||
continue;
|
||||
|
||||
var control = _disclosureControlsForRows[rowIndex];
|
||||
[control setHighlighted:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
if (_outlineViewDelegate === aDelegate)
|
||||
@@ -372,63 +455,24 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
||||
object:self];
|
||||
}
|
||||
|
||||
_outlineViewDelegate = aDelegate;/*
|
||||
_implementedDelegateMethods = 0;
|
||||
_outlineViewDelegate = aDelegate;
|
||||
_implementedOutlineViewDelegateMethods = 0;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(selectionShouldChangeInTableView:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_selectionShouldChangeInTableView_;
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:dataViewForTableColumn:item:)])
|
||||
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:shouldSelectItem:)])
|
||||
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_shouldSelectItem_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:heightOfRowByItem:)])
|
||||
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_heightOfRowByItem_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:dataViewForTableColumn:row:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_dataViewForTableColumn_row_;
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:willDisplayView:forTableColumn:item:)])
|
||||
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:didClickTableColumn:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_didClickTableColumn_;
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:isGroupItem:)])
|
||||
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_isGroupItem_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:didDragTableColumn:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_didDragTableColumn_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:heightOfRow:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_heightOfRow_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:isGroupRow:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_isGroupRow_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:mouseDownInHeaderOfTableColumn:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_mouseDownInHeaderOfTableColumn_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:nextTypeSelectMatchFromRow:toRow:forString:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_nextTypeSelectMatchFromRow_toRow_forString_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:selectionIndexesForProposedSelection:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_selectionIndexesForProposedSelection_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldEditTableColumn:row:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldEditTableColumn_row_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldSelectRow:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldSelectRow_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldSelectTableColumn:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldSelectTableColumn_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldShowViewExpansionForTableColumn:row:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldShowViewExpansionForTableColumn_row_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldTrackView:forTableColumn:row:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldTrackView_forTableColumn_row_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldTypeSelectForEvent:withCurrentSearchString:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldTypeSelectForEvent_withCurrentSearchString_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:toolTipForView:rect:tableColumn:row:mouseLocation:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_toolTipForView_rect_tableColumn_row_mouseLocation_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:typeSelectStringForTableColumn:row:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_typeSelectStringForTableColumn_row_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:willDisplayView:forTableColumn:row:)])
|
||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_willDisplayView_forTableColumn_row_;
|
||||
*/
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidMove:)])
|
||||
[defaultCenter
|
||||
addObserver:_outlineViewDelegate
|
||||
@@ -488,6 +532,55 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
||||
return [super frameOfDataViewAtColumn:aColumn row:aRow];
|
||||
}
|
||||
|
||||
- (void)setDropItem:(id)theItem dropChildIndex:(int)theIndex
|
||||
{
|
||||
_retargetedItem = theItem;
|
||||
_shouldRetargetItem = YES;
|
||||
|
||||
_retargedChildIndex = theIndex;
|
||||
_shouldRetargetChildIndex = YES;
|
||||
}
|
||||
|
||||
- (id)_parentItemForUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex atMouseOffset:(CPPoint)theOffset
|
||||
{
|
||||
if (_shouldRetargetItem)
|
||||
return _retargetedItem;
|
||||
|
||||
var lowerLevel = [self levelForRow:theLowerRowIndex]
|
||||
upperItem = [self itemAtRow:theUpperRowIndex];
|
||||
upperLevel = [self levelForItem:upperItem];
|
||||
|
||||
// If the row above us has a higher level the item can be added to multiple parent items
|
||||
// Determine which one by looping through all possible parents and return the first
|
||||
// of which the indentation level is larger than the current x offset
|
||||
while (upperLevel > lowerLevel)
|
||||
{
|
||||
upperLevel = [self levelForItem:upperItem];
|
||||
|
||||
// See if this item's indentation level matches the mouse offset
|
||||
if (theOffset.x > (upperLevel + 1) * [self indentationPerLevel])
|
||||
return [self parentForItem:upperItem];
|
||||
|
||||
// Check the next parent
|
||||
upperItem = [self parentForItem:upperItem];
|
||||
}
|
||||
|
||||
return [self parentForItem:[self itemAtRow:theLowerRowIndex]];
|
||||
}
|
||||
|
||||
- (CPRect)_rectForDropHighlightViewBetweenUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex offset:(CPPoint)theOffset
|
||||
{
|
||||
// Call super and the update x to reflect the current indentation level
|
||||
var rect = [super _rectForDropHighlightViewBetweenUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex offset:theOffset],
|
||||
parentItem = [self _parentItemForUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex atMouseOffset:theOffset],
|
||||
level = [self levelForItem:parentItem];
|
||||
|
||||
rect.origin.x = (level + 1) * [self indentationPerLevel];
|
||||
rect.size.width -= rect.origin.x; // This assumes that the x returned by super is zero
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
- (void)_loadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns
|
||||
{
|
||||
[super _loadDataViewsInRows:rows columns:columns];
|
||||
@@ -618,140 +711,147 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
||||
|
||||
@end
|
||||
|
||||
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
|
||||
var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
|
||||
{
|
||||
if (!anItem)
|
||||
return;
|
||||
|
||||
// Get the existing info if it exists.
|
||||
var itemInfosForItems = anOutlineView._itemInfosForItems,
|
||||
dataSource = anOutlineView._outlineViewDataSource,
|
||||
itemUID = [anItem UID],
|
||||
itemInfo = itemInfosForItems[itemUID];
|
||||
|
||||
// If we're not in the tree, then just bail.
|
||||
if (!itemInfo)
|
||||
return [];
|
||||
|
||||
// See if the item itself can be swapped out.
|
||||
var parent = itemInfo.parent,
|
||||
parentItemInfo = parent ? itemInfosForItems[[parent UID]] : anOutlineView._rootItemInfo,
|
||||
parentChildren = parentItemInfo.children,
|
||||
index = [parentChildren indexOfObjectIdenticalTo:anItem],
|
||||
newItem = [dataSource outlineView:anOutlineView child:index ofItem:parent];
|
||||
|
||||
if (anItem !== newItem)
|
||||
{
|
||||
itemInfosForItems[[anItem UID]] = nil;
|
||||
itemInfosForItems[[newItem UID]] = itemInfo;
|
||||
|
||||
parentChildren[index] = newItem;
|
||||
anOutlineView._itemsForRows[itemInfo.row] = newItem;
|
||||
}
|
||||
|
||||
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem];
|
||||
itemInfo.isExpanded = itemInfo.isExpandable && itemInfo.isExpanded;
|
||||
}
|
||||
|
||||
var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem, /*BOOL*/ isIntermediate)
|
||||
{
|
||||
var itemInfosForItems = anOutlineView._itemInfosForItems,
|
||||
dataSource = anOutlineView._outlineViewDataSource;
|
||||
|
||||
if (!anItem)
|
||||
var itemInfo = anOutlineView._rootItemInfo;
|
||||
|
||||
else
|
||||
with(anOutlineView)
|
||||
{
|
||||
// Get the existing info if it exists.
|
||||
var itemUID = [anItem UID],
|
||||
var itemInfosForItems = _itemInfosForItems,
|
||||
dataSource = _outlineViewDataSource,
|
||||
itemUID = [anItem UID],
|
||||
itemInfo = itemInfosForItems[itemUID];
|
||||
|
||||
|
||||
// If we're not in the tree, then just bail.
|
||||
if (!itemInfo)
|
||||
return [];
|
||||
|
||||
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:anItem];
|
||||
|
||||
// If we were previously expanded, but now no longer expandable, "de-expand".
|
||||
// NOTE: we are *not* collapsing, thus no notification is posted.
|
||||
if (!itemInfo.isExpandable && itemInfo.isExpanded)
|
||||
|
||||
// See if the item itself can be swapped out.
|
||||
var parent = itemInfo.parent,
|
||||
parentItemInfo = parent ? itemInfosForItems[[parent UID]] : _rootItemInfo,
|
||||
parentChildren = parentItemInfo.children,
|
||||
index = [parentChildren indexOfObjectIdenticalTo:anItem],
|
||||
newItem = [dataSource outlineView:anOutlineView child:index ofItem:parent];
|
||||
|
||||
if (anItem !== newItem)
|
||||
{
|
||||
itemInfo.isExpanded = NO;
|
||||
itemInfosForItems[[anItem UID]] = nil;
|
||||
itemInfosForItems[[newItem UID]] = itemInfo;
|
||||
|
||||
parentChildren[index] = newItem;
|
||||
_itemsForRows[itemInfo.row] = newItem;
|
||||
}
|
||||
|
||||
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem];
|
||||
itemInfo.isExpanded = itemInfo.isExpandable && itemInfo.isExpanded;
|
||||
}
|
||||
}
|
||||
|
||||
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
|
||||
var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem, /*BOOL*/ isIntermediate)
|
||||
{
|
||||
with(anOutlineView)
|
||||
{
|
||||
var itemInfosForItems = _itemInfosForItems,
|
||||
dataSource = _outlineViewDataSource;
|
||||
|
||||
if (!anItem)
|
||||
var itemInfo = _rootItemInfo;
|
||||
|
||||
else
|
||||
{
|
||||
// Get the existing info if it exists.
|
||||
var itemUID = [anItem UID],
|
||||
itemInfo = itemInfosForItems[itemUID];
|
||||
|
||||
// If we're not in the tree, then just bail.
|
||||
if (!itemInfo)
|
||||
return [];
|
||||
|
||||
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:anItem];
|
||||
|
||||
// If we were previously expanded, but now no longer expandable, "de-expand".
|
||||
// NOTE: we are *not* collapsing, thus no notification is posted.
|
||||
if (!itemInfo.isExpandable && itemInfo.isExpanded)
|
||||
{
|
||||
itemInfo.isExpanded = NO;
|
||||
itemInfo.children = [];
|
||||
}
|
||||
}
|
||||
|
||||
// The root item does not count as a descendant.
|
||||
var weight = itemInfo.weight,
|
||||
descendants = anItem ? [anItem] : [];
|
||||
|
||||
if (itemInfo.isExpanded && (!(_implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_) ||
|
||||
![dataSource outlineView:anOutlineView shouldDeferDisplayingChildrenOfItem:anItem]))
|
||||
{
|
||||
var index = 0,
|
||||
count = [dataSource outlineView:anOutlineView numberOfChildrenOfItem:anItem],
|
||||
level = itemInfo.level + 1;
|
||||
|
||||
itemInfo.children = [];
|
||||
}
|
||||
}
|
||||
|
||||
// The root item does not count as a descendant.
|
||||
var weight = itemInfo.weight,
|
||||
descendants = anItem ? [anItem] : [];
|
||||
|
||||
if (itemInfo.isExpanded && (!(anOutlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_) ||
|
||||
![dataSource outlineView:anOutlineView shouldDeferDisplayingChildrenOfItem:anItem]))
|
||||
{
|
||||
var index = 0,
|
||||
count = [dataSource outlineView:anOutlineView numberOfChildrenOfItem:anItem],
|
||||
level = itemInfo.level + 1;
|
||||
|
||||
itemInfo.children = [];
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var childItem = [dataSource outlineView:anOutlineView child:index ofItem:anItem],
|
||||
childItemInfo = itemInfosForItems[[childItem UID]];
|
||||
|
||||
if (!childItemInfo)
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
childItemInfo = { isExpanded:NO, isExpandable:NO, children:[], weight:1 };
|
||||
itemInfosForItems[[childItem UID]] = childItemInfo;
|
||||
var childItem = [dataSource outlineView:anOutlineView child:index ofItem:anItem],
|
||||
childItemInfo = itemInfosForItems[[childItem UID]];
|
||||
|
||||
if (!childItemInfo)
|
||||
{
|
||||
childItemInfo = { isExpanded:NO, isExpandable:NO, children:[], weight:1 };
|
||||
itemInfosForItems[[childItem UID]] = childItemInfo;
|
||||
}
|
||||
|
||||
itemInfo.children[index] = childItem;
|
||||
|
||||
var childDescendants = _loadItemInfoForItem(anOutlineView, childItem, YES);
|
||||
|
||||
childItemInfo.parent = anItem;
|
||||
childItemInfo.level = level;
|
||||
descendants = descendants.concat(childDescendants);
|
||||
}
|
||||
|
||||
itemInfo.children[index] = childItem;
|
||||
|
||||
var childDescendants = _loadItemInfoForItem(anOutlineView, childItem, YES);
|
||||
|
||||
childItemInfo.parent = anItem;
|
||||
childItemInfo.level = level;
|
||||
descendants = descendants.concat(childDescendants);
|
||||
}
|
||||
}
|
||||
|
||||
itemInfo.weight = descendants.length;
|
||||
|
||||
if (!isIntermediate)
|
||||
{
|
||||
// row = -1 is the root item, so just go to row 0 since it is ignored.
|
||||
var index = MAX(itemInfo.row, 0),
|
||||
itemsForRows = anOutlineView._itemsForRows;
|
||||
|
||||
descendants.unshift(index, weight);
|
||||
|
||||
itemsForRows.splice.apply(itemsForRows, descendants);
|
||||
|
||||
var count = itemsForRows.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
itemInfosForItems[[itemsForRows[index] UID]].row = index;
|
||||
|
||||
var deltaWeight = itemInfo.weight - weight;
|
||||
|
||||
if (deltaWeight !== 0)
|
||||
|
||||
itemInfo.weight = descendants.length;
|
||||
|
||||
if (!isIntermediate)
|
||||
{
|
||||
var parent = itemInfo.parent;
|
||||
|
||||
while (parent)
|
||||
// row = -1 is the root item, so just go to row 0 since it is ignored.
|
||||
var index = MAX(itemInfo.row, 0),
|
||||
itemsForRows = _itemsForRows;
|
||||
|
||||
descendants.unshift(index, weight);
|
||||
|
||||
itemsForRows.splice.apply(itemsForRows, descendants);
|
||||
|
||||
var count = itemsForRows.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
itemInfosForItems[[itemsForRows[index] UID]].row = index;
|
||||
|
||||
var deltaWeight = itemInfo.weight - weight;
|
||||
|
||||
if (deltaWeight !== 0)
|
||||
{
|
||||
var parentItemInfo = itemInfosForItems[[parent UID]];
|
||||
|
||||
parentItemInfo.weight += deltaWeight;
|
||||
parent = parentItemInfo.parent;
|
||||
var parent = itemInfo.parent;
|
||||
|
||||
while (parent)
|
||||
{
|
||||
var parentItemInfo = itemInfosForItems[[parent UID]];
|
||||
|
||||
parentItemInfo.weight += deltaWeight;
|
||||
parent = parentItemInfo.parent;
|
||||
}
|
||||
|
||||
if (anItem)
|
||||
_rootItemInfo.weight += deltaWeight;
|
||||
}
|
||||
|
||||
if (anItem)
|
||||
anOutlineView._rootItemInfo.weight += deltaWeight;
|
||||
}
|
||||
}
|
||||
|
||||
}//end of with
|
||||
return descendants;
|
||||
}
|
||||
|
||||
@@ -780,6 +880,93 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return [_outlineView._outlineViewDataSource outlineView:_outlineView objectValueForTableColumn:aTableColumn byItem:_outlineView._itemsForRows[aRow]];
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableColumn writeRowsWithIndexes:(CPIndexSet)theIndexes toPasteboard:(CPPasteboard)thePasteboard
|
||||
{
|
||||
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_))
|
||||
return NO;
|
||||
|
||||
var rowIndexes = [];
|
||||
[theIndexes getIndexes:rowIndexes maxCount:[theIndexes count] inIndexRange:nil];
|
||||
|
||||
var rowIndex = [rowIndexes count],
|
||||
items = [];
|
||||
|
||||
while (rowIndex--)
|
||||
[items addObject:[_outlineView itemAtRow:[rowIndexes objectAtIndex:rowIndex]]];
|
||||
|
||||
return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard];
|
||||
}
|
||||
|
||||
- (int)_childIndexForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)theOffset
|
||||
{
|
||||
if (_outlineView._shouldRetargetChildIndex)
|
||||
return _outlineView._retargedChildIndex;
|
||||
|
||||
var childIndex = CPNotFound;
|
||||
|
||||
if (theDropOperation === CPTableViewDropAbove)
|
||||
{
|
||||
var parentItem = [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset],
|
||||
itemInfo = (parentItem !== nil) ? _outlineView._itemInfosForItems[[parentItem UID]] : _outlineView._rootItemInfo,
|
||||
children = itemInfo.children;
|
||||
|
||||
childIndex = [children indexOfObject:[_outlineView itemAtRow:theRow]];
|
||||
|
||||
if (childIndex === CPNotFound)
|
||||
childIndex = children.length;
|
||||
}
|
||||
else if (theDropOperation === CPTableViewDropOn)
|
||||
childIndex = -1;
|
||||
|
||||
return childIndex;
|
||||
}
|
||||
|
||||
- (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)theOffset
|
||||
{
|
||||
if (theDropOperation === CPTableViewDropAbove)
|
||||
return [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset]
|
||||
|
||||
return [_outlineView itemAtRow:theRow];
|
||||
}
|
||||
|
||||
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id < CPDraggingInfo >)theInfo
|
||||
proposedRow:(int)theRow proposedDropOperation:(CPTableViewDropOperation)theOperation
|
||||
{
|
||||
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_))
|
||||
return CPDragOperationNone;
|
||||
|
||||
// Make sure the retargeted item and index are reset
|
||||
_outlineView._retargetedItem = nil;
|
||||
_outlineView._shouldRetargetItem = NO;
|
||||
|
||||
_outlineView._retargedChildIndex = nil;
|
||||
_outlineView._shouldRetargetChildIndex = NO;
|
||||
|
||||
var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil],
|
||||
parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location];
|
||||
childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
|
||||
|
||||
return [_outlineView._outlineViewDataSource outlineView:_outlineView validateDrop:theInfo proposedItem:parentItem proposedChildIndex:childIndex];
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id <CPDraggingInfo>)theInfo row:(int)theRow dropOperation:(CPTableViewDropOperation)theOperation
|
||||
{
|
||||
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_))
|
||||
return NO;
|
||||
|
||||
var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil],
|
||||
parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location];
|
||||
childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
|
||||
|
||||
_outlineView._retargetedItem = nil;
|
||||
_outlineView._shouldRetargetItem = NO;
|
||||
|
||||
_outlineView._retargedChildIndex = nil;
|
||||
_outlineView._shouldRetargetChildIndex = NO;
|
||||
|
||||
return [_outlineView._outlineViewDataSource outlineView:_outlineView acceptDrop:theInfo item:parentItem childIndex:childIndex];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPOutlineViewTableViewDelegate : CPObject
|
||||
@@ -797,6 +984,54 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPView)tableView:(CPTableView)theTableView dataViewForTableColumn:(CPTableColumn)theTableColumn row:(int)theRow
|
||||
{
|
||||
var dataView = nil;
|
||||
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_))
|
||||
dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView
|
||||
dataViewForTableColumn:theTableColumn
|
||||
item:[_outlineView itemAtRow:theRow]];
|
||||
|
||||
if (!dataView)
|
||||
dataView = [theTableColumn dataViewForRow:theRow];
|
||||
|
||||
return dataView;
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(CPTableView)theTableView shouldSelectRow:(int)theRow
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_))
|
||||
return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldSelectItem:[_outlineView itemAtRow:theRow]];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (float)tableView:(CPTableView)theTableView heightOfRow:(int)theRow
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_heightOfRowByItem_))
|
||||
return [_outlineView._outlineViewDelegate outlineView:_outlineView heightOfRowByItem:[_outlineView itemAtRow:theRow]];
|
||||
|
||||
return [theTableView rowHeight];
|
||||
}
|
||||
|
||||
- (void)tableView:(CPTableView)aTableView willDisplayView:(id)aView forTableColumn:(CPTableColumn)aTableColumn row:(int)aRowIndex
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_))
|
||||
{
|
||||
var item = [_outlineView itemAtRow:aRowIndex];
|
||||
[_outlineView._outlineViewDelegate outlineView:_outlineView willDisplayView:aView forTableColumn:aTableColumn item:item];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView isGroupRow:(int)row
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_isGroupItem_))
|
||||
return [_outlineView._outlineViewDelegate outlineView:_outlineView isGroupItem:[_outlineView itemAtRow:theRow]];
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPDisclosureButton : CPButton
|
||||
@@ -846,7 +1081,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
|
||||
CGContextClosePath(context);
|
||||
|
||||
CGContextSetFillColor(context, ([self themeState] & CPThemeState("highlighted")) ? [CPColor blackColor] : [CPColor grayColor]);
|
||||
CGContextSetFillColor(context, [self isHighlighted] ? [CPColor whiteColor] : [CPColor grayColor]);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,13 @@ CPCancelButton = 0;
|
||||
<li>A panel can be made to work even when there's an attention panel on-screen. This permits actions within the panel to affect the attention panel.</li>
|
||||
</ul>
|
||||
*/
|
||||
|
||||
/*
|
||||
@global
|
||||
@class CPWindow
|
||||
*/
|
||||
CPDocModalWindowMask = 1 << 6;
|
||||
|
||||
@implementation CPPanel : CPWindow
|
||||
{
|
||||
BOOL _becomesKeyOnlyIfNeeded;
|
||||
|
||||
+88
-16
@@ -43,11 +43,14 @@ CPURLPboardType = @"CPURLPboardType";
|
||||
CPImagesPboardType = @"CPImagesPboardType";
|
||||
CPVideosPboardType = @"CPVideosPboardType";
|
||||
|
||||
UTF8PboardType = @"public.utf8-plain-text";
|
||||
|
||||
// Deprecated
|
||||
CPImagePboardType = @"CPImagePboardType";
|
||||
|
||||
|
||||
var CPPasteboards = nil;
|
||||
var CPPasteboards = nil,
|
||||
supportsNativePasteboard = NO;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -63,6 +66,8 @@ var CPPasteboards = nil;
|
||||
|
||||
unsigned _changeCount;
|
||||
CPString _stateUID;
|
||||
|
||||
WebScriptObject _nativePasteboard;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -76,6 +81,9 @@ var CPPasteboards = nil;
|
||||
[self setVersion:1.0];
|
||||
|
||||
CPPasteboards = [CPDictionary dictionary];
|
||||
|
||||
if (typeof window.cpPasteboardWithName !== "undefined")
|
||||
supportsNativePasteboard = YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -94,7 +102,7 @@ var CPPasteboards = nil;
|
||||
+ (id)pasteboardWithName:(CPString)aName
|
||||
{
|
||||
var pasteboard = [CPPasteboards objectForKey:aName];
|
||||
|
||||
|
||||
if (pasteboard)
|
||||
return pasteboard;
|
||||
|
||||
@@ -118,6 +126,12 @@ var CPPasteboards = nil;
|
||||
_provided = [CPDictionary dictionary];
|
||||
|
||||
_changeCount = 0;
|
||||
|
||||
if (supportsNativePasteboard)
|
||||
{
|
||||
_nativePasteboard = window.cpPasteboardWithName(aName);
|
||||
[self _synchronizePasteboard];
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -146,7 +160,16 @@ var CPPasteboards = nil;
|
||||
|
||||
[_owners setObject:anOwner forKey:type];
|
||||
}
|
||||
|
||||
|
||||
if (_nativePasteboard)
|
||||
{
|
||||
var nativeTypes = [types copy];
|
||||
if ([types containsObject:CPStringPboardType])
|
||||
nativeTypes.push(UTF8PboardType);
|
||||
|
||||
_nativePasteboard.addTypes_(nativeTypes);
|
||||
}
|
||||
|
||||
return ++_changeCount;
|
||||
}
|
||||
|
||||
@@ -157,6 +180,12 @@ var CPPasteboards = nil;
|
||||
@return the pasteboard's change count
|
||||
*/
|
||||
- (unsigned)declareTypes:(CPArray)types owner:(id)anOwner
|
||||
{
|
||||
[self _declareTypes:types owner:anOwner updateNativePasteboard:YES];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (unsigned)_declareTypes:(CPArray)types owner:(id)anOwner updateNativePasteboard:(BOOL)shouldUpdate
|
||||
{
|
||||
[_types setArray:types];
|
||||
|
||||
@@ -167,7 +196,16 @@ var CPPasteboards = nil;
|
||||
|
||||
while (count--)
|
||||
[_owners setObject:anOwner forKey:_types[count]];
|
||||
|
||||
|
||||
if (_nativePasteboard && shouldUpdate)
|
||||
{
|
||||
var nativeTypes = [types copy];
|
||||
if ([types containsObject:CPStringPboardType])
|
||||
nativeTypes.push(UTF8PboardType);
|
||||
|
||||
_nativePasteboard.declareTypes_(nativeTypes);
|
||||
_changeCount = _nativePasteboard.changeCount();
|
||||
}
|
||||
return ++_changeCount;
|
||||
}
|
||||
|
||||
@@ -180,7 +218,10 @@ var CPPasteboards = nil;
|
||||
- (BOOL)setData:(CPData)aData forType:(CPString)aType
|
||||
{
|
||||
[_provided setObject:aData forKey:aType];
|
||||
|
||||
|
||||
if (aType === CPStringPboardType)
|
||||
[self setData:aData forType:UTF8PboardType];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -192,7 +233,7 @@ var CPPasteboards = nil;
|
||||
*/
|
||||
- (BOOL)setPropertyList:(id)aPropertyList forType:(CPString)aType
|
||||
{
|
||||
return [self setData:[CPPropertyListSerialization dataFromPropertyList:aPropertyList format:CPPropertyListXMLFormat_v1_0 errorDescription:nil] forType:aType];
|
||||
return [self setData:[CPPropertyListSerialization dataFromPropertyList:aPropertyList format:CPPropertyList280NorthFormat_v1_0] forType:aType];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -203,7 +244,7 @@ var CPPasteboards = nil;
|
||||
*/
|
||||
- (void)setString:(CPString)aString forType:(CPString)aType
|
||||
{
|
||||
return [self setPropertyList:aString forType:aType];
|
||||
[self setPropertyList:aString forType:aType];
|
||||
}
|
||||
|
||||
// Determining Types
|
||||
@@ -223,6 +264,7 @@ var CPPasteboards = nil;
|
||||
*/
|
||||
- (CPArray)types
|
||||
{
|
||||
[self _synchronizePasteboard];
|
||||
return _types;
|
||||
}
|
||||
|
||||
@@ -251,16 +293,46 @@ var CPPasteboards = nil;
|
||||
|
||||
if (owner)
|
||||
{
|
||||
[owner pasteboard:self provideDataForType:aType];
|
||||
|
||||
++_changeCount;
|
||||
|
||||
[owner pasteboard:self provideDataForType:aType];
|
||||
return [_provided objectForKey:aType];
|
||||
}
|
||||
|
||||
if (aType === CPStringPboardType)
|
||||
return [self dataForType:UTF8PboardType];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)_synchronizePasteboard
|
||||
{
|
||||
if (_nativePasteboard && _nativePasteboard.changeCount() > _changeCount)
|
||||
{
|
||||
var nativeTypes = [_nativePasteboard.types() copy];
|
||||
if ([nativeTypes containsObject:UTF8PboardType])
|
||||
nativeTypes.push(CPStringPboardType);
|
||||
|
||||
[self _declareTypes:nativeTypes owner:self updateNativePasteboard:NO];
|
||||
|
||||
_changeCount = _nativePasteboard.changeCount();
|
||||
}
|
||||
}
|
||||
|
||||
/*! @ignore
|
||||
method provided for integration with native pasteboard
|
||||
*/
|
||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||
{
|
||||
if (aType === CPStringPboardType)
|
||||
{
|
||||
var string = _nativePasteboard.stringForType_(UTF8PboardType);
|
||||
|
||||
[self setString:string forType:CPStringPboardType];
|
||||
[self setString:string forType:UTF8PboardType];
|
||||
}
|
||||
else
|
||||
[self setString:_nativePasteboard.stringForType_(aType) forType:aType];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the property list for the specified data type
|
||||
@param aType the requested data type
|
||||
@@ -271,7 +343,7 @@ var CPPasteboards = nil;
|
||||
var data = [self dataForType:aType];
|
||||
|
||||
if (data)
|
||||
return [CPPropertyListSerialization propertyListFromData:data format:CPPropertyListXMLFormat_v1_0 errorDescription:nil];
|
||||
return [CPPropertyListSerialization propertyListFromData:data format:CPPropertyList280NorthFormat_v1_0];
|
||||
|
||||
return nil;
|
||||
}
|
||||
@@ -343,7 +415,7 @@ var DOMDataTransferPasteboard = nil;
|
||||
if (type === CPStringPboardType)
|
||||
_dataTransfer.setData(type, [aPasteboard stringForType:type]);
|
||||
else
|
||||
_dataTransfer.setData(type, [[aPasteboard dataForType:type] string]);
|
||||
_dataTransfer.setData(type, [[aPasteboard dataForType:type] rawString]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,9 +429,9 @@ var DOMDataTransferPasteboard = nil;
|
||||
var dataString = _dataTransfer.getData(aType);
|
||||
|
||||
if (aType === CPStringPboardType)
|
||||
return [CPData dataFromPropertyList:dataString format:kCFPropertyList280NorthFormat_v1_0 errorDescription:0];
|
||||
return [CPData dataFromPropertyList:dataString format:kCFPropertyList280NorthFormat_v1_0];
|
||||
|
||||
return [CPData dataWithString:dataString];
|
||||
return [CPData dataWithRawString:dataString];
|
||||
}
|
||||
|
||||
- (id)propertyListForType:(CPString)aType
|
||||
@@ -367,7 +439,7 @@ var DOMDataTransferPasteboard = nil;
|
||||
if (aType === CPStringPboardType)
|
||||
return _dataTransfer.getData(aType);
|
||||
|
||||
return [CPPropertyListSerialization propertyListFromData:[self dataForType:aType] format:CPPropertyListUnknownFormat errorDescription:nil];
|
||||
return [CPPropertyListSerialization propertyListFromData:[self dataForType:aType] format:CPPropertyListUnknownFormat];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+41
-42
@@ -638,21 +638,49 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
{
|
||||
if (![self isEnabled] || ![self numberOfItems])
|
||||
return;
|
||||
|
||||
|
||||
[self highlight:YES];
|
||||
|
||||
var menu = [self menu],
|
||||
theWindow = [self window],
|
||||
menuWindow = [_CPMenuWindow menuWindowWithMenu:menu font:[self font]];
|
||||
|
||||
[menuWindow setDelegate:self];
|
||||
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
|
||||
|
||||
// Pull Down Menus show up directly below their buttons.
|
||||
bounds = [self bounds],
|
||||
minimumWidth = CGRectGetWidth(bounds);
|
||||
|
||||
// FIXME: setFont: should set the font on the menu.
|
||||
[menu setFont:[self font]];
|
||||
|
||||
if ([self pullsDown])
|
||||
var menuOrigin = [theWindow convertBaseToGlobal:[self convertPoint:CGPointMake(0.0, CGRectGetMaxY([self bounds])) toView:nil]];
|
||||
|
||||
// Pop Up Menus attempt to show up "on top" of the selected item.
|
||||
{
|
||||
var positionedItem = nil,
|
||||
location = CGPointMake(0.0, CGRectGetMaxY(bounds));
|
||||
}
|
||||
else
|
||||
{
|
||||
var contentRect = [self contentRectForBounds:bounds],
|
||||
positionedItem = [self selectedItem],
|
||||
standardLeftMargin = [_CPMenuWindow _standardLeftMargin] + [_CPMenuItemStandardView _standardLeftMargin],
|
||||
location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0);
|
||||
|
||||
minimumWidth += standardLeftMargin;
|
||||
}
|
||||
|
||||
[menu setMinimumWidth:minimumWidth];
|
||||
|
||||
[menu
|
||||
_popUpMenuPositioningItem:positionedItem
|
||||
atLocation:location
|
||||
topY:CGRectGetMinY(bounds)
|
||||
bottomY:CGRectGetMaxY(bounds)
|
||||
inView:self
|
||||
callback:function(aMenu)
|
||||
{
|
||||
[self highlight:NO];
|
||||
|
||||
var highlightedItem = [aMenu highlightedItem];
|
||||
|
||||
if ([highlightedItem _isSelectable])
|
||||
[self selectItem:highlightedItem];
|
||||
}];
|
||||
/*
|
||||
else
|
||||
{
|
||||
// This is confusing, I KNOW, so let me explain it to you.
|
||||
@@ -660,43 +688,14 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
// 1. So calculate where our content is, then calculate where the menu item is.
|
||||
// 2. Move LEFT by whatever indentation we have (offsetWidths, aka, window margin, item margin, etc).
|
||||
// 3. MOVE UP by the difference in sizes of the content and menu item, this will only work if the content is vertically centered.
|
||||
var contentRect = [self convertRect:[self contentRectForBounds:[self bounds]] toView:nil],
|
||||
var contentRect = [self convertRect:[self contentRectForBounds:bounds] toView:nil],
|
||||
menuOrigin = [theWindow convertBaseToGlobal:contentRect.origin],
|
||||
menuItemRect = [menuWindow rectForItemAtIndex:_selectedIndex];
|
||||
|
||||
|
||||
menuOrigin.x -= CGRectGetMinX(menuItemRect) + [menuWindow overlapOffsetWidth] + [[[menu itemAtIndex:_selectedIndex] _menuItemView] overlapOffsetWidth];
|
||||
menuOrigin.y -= CGRectGetMinY(menuItemRect) + (CGRectGetHeight(menuItemRect) - CGRectGetHeight(contentRect)) / 2.0;
|
||||
}
|
||||
|
||||
[menuWindow setFrameOrigin:menuOrigin];
|
||||
|
||||
var menuMaxX = CGRectGetMaxX([menuWindow frame]),
|
||||
buttonMaxX = [theWindow convertBaseToGlobal:CGPointMake(CGRectGetMaxX([self convertRect:[self bounds] toView:nil]), 0.0)].x;
|
||||
|
||||
if (menuMaxX < buttonMaxX)
|
||||
[menuWindow setMinWidth:CGRectGetWidth([menuWindow frame]) + buttonMaxX - menuMaxX - ([self pullsDown] ? 0.0 : VISIBLE_MARGIN)];
|
||||
|
||||
[menuWindow orderFront:self];
|
||||
[menuWindow beginTrackingWithEvent:anEvent sessionDelegate:self didEndSelector:@selector(menuWindowDidFinishTracking:highlightedItem:)];
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (void)menuWindowDidFinishTracking:(_CPMenuWindow)aMenuWindow highlightedItem:(CPMenuItem)aMenuItem
|
||||
{
|
||||
[_CPMenuWindow poolMenuWindow:aMenuWindow];
|
||||
|
||||
[self highlight:NO];
|
||||
|
||||
var index = [_menu indexOfItem:aMenuItem];
|
||||
|
||||
if (index == CPNotFound)
|
||||
return;
|
||||
|
||||
[self selectItemAtIndex:index];
|
||||
|
||||
[CPApp sendAction:[aMenuItem action] to:[aMenuItem target] from:aMenuItem];
|
||||
}
|
||||
|
||||
- (void)_popUpItemAction:(id)aSender
|
||||
|
||||
@@ -104,17 +104,14 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
||||
for (; start <= end; ++start)
|
||||
{
|
||||
CPProgressIndicatorBezelBorderViewPool[start] = [];
|
||||
|
||||
CPProgressIndicatorBezelBorderViewPool[start][CPMiniControlSize] = [];
|
||||
CPProgressIndicatorBezelBorderViewPool[start][CPSmallControlSize] = [];
|
||||
CPProgressIndicatorBezelBorderViewPool[start][CPRegularControlSize] = [];
|
||||
}
|
||||
|
||||
CPProgressIndicatorClassName = [self className];
|
||||
|
||||
|
||||
CPProgressIndicatorStyleIdentifiers = [];
|
||||
|
||||
|
||||
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle] = @"Bar";
|
||||
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorSpinningStyle] = @"Spinny";
|
||||
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle] = @"HUDBar";
|
||||
@@ -126,30 +123,20 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
||||
CPProgressIndicatorStyleSizes = [];
|
||||
|
||||
// Bar Sttyle
|
||||
var prefix = CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle];
|
||||
var prefixes = [
|
||||
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
|
||||
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
|
||||
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle],
|
||||
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle]
|
||||
];
|
||||
|
||||
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
|
||||
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
|
||||
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
|
||||
|
||||
prefix = CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle];
|
||||
|
||||
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = _CGSizeMake(1.0, 9.0);
|
||||
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = _CGSizeMake(1.0, 9.0);
|
||||
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = _CGSizeMake(1.0, 9.0);
|
||||
|
||||
// HUD Bar Style
|
||||
prefix = CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle];
|
||||
|
||||
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
|
||||
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
|
||||
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
|
||||
|
||||
prefix = CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle];
|
||||
|
||||
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = _CGSizeMake(1.0, 9.0);
|
||||
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = _CGSizeMake(1.0, 9.0);
|
||||
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = _CGSizeMake(1.0, 9.0);
|
||||
for (var i = 0, count = prefixes.length; i<count; i++)
|
||||
{
|
||||
var prefix = prefixes[i];
|
||||
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
|
||||
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
|
||||
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -428,21 +415,25 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
||||
|
||||
if (!_barView)
|
||||
{
|
||||
_barView = [[CPView alloc] initWithFrame:CGRectMake(2.0, 2.0, 0.0, 9.0)];
|
||||
|
||||
[_barView setBackgroundColor:[CPColor redColor]];
|
||||
|
||||
_barView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 16.0)];
|
||||
[self addSubview:_barView];
|
||||
}
|
||||
|
||||
[_barView setBackgroundColor:_CPControlColorWithPatternImage(
|
||||
[_barView setBackgroundColor:_CPControlThreePartImagePattern(
|
||||
NO,
|
||||
CPProgressIndicatorStyleSizes,
|
||||
CPProgressIndicatorClassName,
|
||||
@"Bar",
|
||||
CPProgressIndicatorStyleIdentifiers[_style],
|
||||
_CPControlIdentifierForControlSize(_controlSize))];
|
||||
|
||||
[_barView setFrameSize:CGSizeMake(CGRectGetWidth([self bounds]) * (_doubleValue - _minValue) / (_maxValue - _minValue) - 4.0, 9.0)];
|
||||
|
||||
var width = CGRectGetWidth([self bounds]),
|
||||
barWidth = width * ((_doubleValue - _minValue) / (_maxValue - _minValue));
|
||||
|
||||
if (barWidth > 0.0 && barWidth < 4.0)
|
||||
barWidth = 4.0;
|
||||
|
||||
[_barView setFrameSize:CGSizeMake(barWidth, 16.0)];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
|
||||
+7
-2
@@ -98,7 +98,7 @@
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self setRadioGroup:aRadioGroup || [CPRadioGroup new]];
|
||||
[self setRadioGroup:aRadioGroup];
|
||||
|
||||
[self setHighlightsBy:CPContentsCellMask];
|
||||
[self setShowsStateBy:CPContentsCellMask];
|
||||
@@ -115,7 +115,7 @@
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
return [self initWithFrame:aFrame radioGroup:nil];
|
||||
return [self initWithFrame:aFrame radioGroup:[CPRadioGroup new]];
|
||||
}
|
||||
|
||||
- (CPInteger)nextState
|
||||
@@ -175,6 +175,9 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
||||
{
|
||||
CPSet _radios;
|
||||
CPRadio _selectedRadio;
|
||||
|
||||
id _target @accessors(property=target);
|
||||
SEL _action @accessors(property=action);
|
||||
}
|
||||
|
||||
- (id)init
|
||||
@@ -213,6 +216,8 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
||||
|
||||
[_selectedRadio setState:CPOffState];
|
||||
_selectedRadio = aRadio;
|
||||
|
||||
[CPApp sendAction:_action to:_target from:self];
|
||||
}
|
||||
|
||||
- (CPRadio)selectedRadio
|
||||
|
||||
+26
-1
@@ -27,6 +27,9 @@ CPDeleteKeyCode = 8;
|
||||
CPTabKeyCode = 9;
|
||||
CPReturnKeyCode = 13;
|
||||
CPEscapeKeyCode = 27;
|
||||
CPSpaceKeyCode = 32;
|
||||
CPPageUpKeyCode = 33;
|
||||
CPPageDownKeyCode = 34;
|
||||
CPLeftArrowKeyCode = 37;
|
||||
CPUpArrowKeyCode = 38;
|
||||
CPRightArrowKeyCode = 39;
|
||||
@@ -105,6 +108,10 @@ CPDownArrowKeyCode = 40;
|
||||
|
||||
switch([event keyCode])
|
||||
{
|
||||
case CPPageUpKeyCode: [self doCommandBySelector:@selector(pageUp:)];
|
||||
break;
|
||||
case CPPageDownKeyCode: [self doCommandBySelector:@selector(pageDown:)];
|
||||
break;
|
||||
case CPLeftArrowKeyCode: [self doCommandBySelector:@selector(moveLeft:)];
|
||||
break;
|
||||
case CPRightArrowKeyCode: [self doCommandBySelector:@selector(moveRight:)];
|
||||
@@ -145,6 +152,15 @@ CPDownArrowKeyCode = 40;
|
||||
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||
}
|
||||
|
||||
/*!
|
||||
Notifies the receiver that the user has clicked the right mouse down in its area.
|
||||
@param anEvent contains information about the right click
|
||||
*/
|
||||
- (void)rightMouseDown:(CPEvent)anEvent
|
||||
{
|
||||
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||
}
|
||||
|
||||
/*!
|
||||
Notifies the receiver that the user has initiated a drag
|
||||
over it. A drag is a mouse movement while the left button is down.
|
||||
@@ -164,6 +180,15 @@ CPDownArrowKeyCode = 40;
|
||||
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||
}
|
||||
|
||||
/*!
|
||||
Notifies the receiver that the user has released the right mouse button.
|
||||
@param anEvent contains information about the release
|
||||
*/
|
||||
- (void)rightMouseUp:(CPEvent)anEvent
|
||||
{
|
||||
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||
}
|
||||
|
||||
/*!
|
||||
Notifies the receiver that the user has moved the mouse (with no buttons down).
|
||||
@param anEvent contains information about the movement
|
||||
@@ -241,7 +266,7 @@ CPDownArrowKeyCode = 40;
|
||||
*/
|
||||
- (void)insertNewline:(id)aSender
|
||||
{
|
||||
[self insertNewline:aSender];
|
||||
[[self nextResponder] insertNewline:aSender];
|
||||
}
|
||||
|
||||
- (void)cancel:(id)sender
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
@import <AppKit/CPPanel.j>
|
||||
|
||||
|
||||
@implementation CPSavePanel : CPPanel
|
||||
{
|
||||
CPURL _URL;
|
||||
|
||||
BOOL _isExtensionHidden @accessors(getter=isExtensionHidden, setter=setExtensionHidden:);
|
||||
BOOL _canSelectHiddenExtension @accessors(property=canSelectHiddenExtension);
|
||||
BOOL _allowsOtherFileTypes @accessors(property=allowsOtherFileTypes);
|
||||
BOOL _canCreateDirectories @accessors(property=canCreateDirectories);
|
||||
|
||||
CPArray _allowedFileTypes @accessors(property=allowedFileTypes);
|
||||
}
|
||||
|
||||
+ (id)savePanel
|
||||
{
|
||||
return [[CPSavePanel alloc] init];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_canCreateDirectories = YES;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPInteger)runModal
|
||||
{
|
||||
// FIXME: Is this correct???
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
|
||||
if (typeof window["cpSavePanel"] === "function")
|
||||
{
|
||||
var resultObject = window.cpSavePanel({
|
||||
isExtensionHidden: _isExtensionHidden,
|
||||
canSelectHiddenExtension: _canSelectHiddenExtension,
|
||||
allowsOtherFileTypes: _allowsOtherFileTypes,
|
||||
canCreateDirectories: _canCreateDirectories,
|
||||
allowedFileTypes: _allowedFileTypes
|
||||
}),
|
||||
result = resultObject.button;
|
||||
|
||||
_URL = result ? [CPURL URLWithString:resultObject.URL] : nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: This is not the best way to do this.
|
||||
var documentName = window.prompt("Document Name:"),
|
||||
result = documentName !== null;
|
||||
|
||||
_URL = result ? [[self class] proposedFileURLWithDocumentName:documentName] : nil;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (CPURL)URL
|
||||
{
|
||||
return _URL;
|
||||
}
|
||||
|
||||
@end
|
||||
+5
-1
@@ -1,8 +1,8 @@
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
|
||||
#import "CoreGraphics/CGGeometry.h"
|
||||
#import "Platform/Platform.h"
|
||||
|
||||
@implementation CPScreen : CPObject
|
||||
{
|
||||
@@ -10,7 +10,11 @@
|
||||
|
||||
- (CGRect)visibleFrame
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
return _CGRectMake(window.screen.availLeft, window.screen.availTop, window.screen.availWidth, window.screen.availHeight);
|
||||
#else
|
||||
return _CGRectMakeZero();
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
+69
-55
@@ -313,16 +313,14 @@
|
||||
return;
|
||||
|
||||
_hasHorizontalScroller = shouldHaveHorizontalScroller;
|
||||
|
||||
|
||||
if (_hasHorizontalScroller && !_horizontalScroller)
|
||||
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, _CGRectGetWidth([self bounds]), [CPScroller scrollerWidth])]];
|
||||
|
||||
else if (!_hasHorizontalScroller && _horizontalScroller)
|
||||
{
|
||||
[_horizontalScroller setHidden:YES];
|
||||
|
||||
[self reflectScrolledClipView:_contentView];
|
||||
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth]+1), [CPScroller scrollerWidth])]];
|
||||
[[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth])];
|
||||
}
|
||||
|
||||
[self reflectScrolledClipView:_contentView];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -378,14 +376,12 @@
|
||||
_hasVerticalScroller = shouldHaveVerticalScroller;
|
||||
|
||||
if (_hasVerticalScroller && !_verticalScroller)
|
||||
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], _CGRectGetHeight([self bounds]))]];
|
||||
|
||||
else if (!_hasVerticalScroller && _verticalScroller)
|
||||
{
|
||||
[_verticalScroller setHidden:YES];
|
||||
|
||||
[self reflectScrolledClipView:_contentView];
|
||||
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight([self bounds]), [CPScroller scrollerWidth]+1))]];
|
||||
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight([self bounds]))];
|
||||
}
|
||||
|
||||
[self reflectScrolledClipView:_contentView];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -687,38 +683,48 @@
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
{
|
||||
var keyCode = [anEvent keyCode],
|
||||
documentFrame = [[self documentView] frame],
|
||||
[self interpretKeyEvents:[anEvent]];
|
||||
}
|
||||
|
||||
- (void)pageUp:(id)sender
|
||||
{
|
||||
var contentBounds = [_contentView bounds];
|
||||
[self moveByOffset:CGSizeMake(0.0, -(_CGRectGetHeight(contentBounds) - _verticalPageScroll))];
|
||||
}
|
||||
|
||||
- (void)pageDown:(id)sender
|
||||
{
|
||||
var contentBounds = [_contentView bounds];
|
||||
[self moveByOffset:CGSizeMake(0.0, _CGRectGetHeight(contentBounds) - _verticalPageScroll)];
|
||||
}
|
||||
|
||||
- (void)moveLeft:(id)sender
|
||||
{
|
||||
[self moveByOffset:CGSizeMake(-_horizontalLineScroll, 0.0)];
|
||||
}
|
||||
|
||||
- (void)moveRight:(id)sender
|
||||
{
|
||||
[self moveByOffset:CGSizeMake(_horizontalLineScroll, 0.0)];
|
||||
}
|
||||
|
||||
- (void)moveUp:(id)sender
|
||||
{
|
||||
[self moveByOffset:CGSizeMake(0.0, -_verticalLineScroll)];
|
||||
}
|
||||
|
||||
- (void)moveDown:(id)sender
|
||||
{
|
||||
[self moveByOffset:CGSizeMake(0.0, _verticalLineScroll)];
|
||||
}
|
||||
|
||||
- (void)moveByOffset:(CGSize)aSize
|
||||
{
|
||||
var documentFrame = [[self documentView] frame],
|
||||
contentBounds = [_contentView bounds];
|
||||
|
||||
switch (keyCode)
|
||||
{
|
||||
case 33: /*pageup*/
|
||||
contentBounds.origin.y -= _CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
||||
break;
|
||||
|
||||
case 34: /*pagedown*/
|
||||
contentBounds.origin.y += _CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
||||
break;
|
||||
|
||||
case 38: /*up arrow*/
|
||||
contentBounds.origin.y -= _verticalLineScroll;
|
||||
break;
|
||||
|
||||
case 40: /*down arrow*/
|
||||
contentBounds.origin.y += _verticalLineScroll;
|
||||
break;
|
||||
|
||||
case 37: /*left arrow*/
|
||||
contentBounds.origin.x -= _horizontalLineScroll;
|
||||
break;
|
||||
|
||||
case 49: /*right arrow*/
|
||||
contentBounds.origin.x += _horizontalLineScroll;
|
||||
break;
|
||||
|
||||
default: return [super keyDown:anEvent];
|
||||
}
|
||||
contentBounds.origin.x += aSize.width;
|
||||
contentBounds.origin.y += aSize.height;
|
||||
|
||||
[_contentView scrollToPoint:contentBounds.origin];
|
||||
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin, 0)];
|
||||
@@ -726,16 +732,18 @@
|
||||
|
||||
@end
|
||||
|
||||
var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
||||
CPScrollViewVLineScrollKey = "CPScrollViewVLineScroll",
|
||||
CPScrollViewHLineScrollKey = "CPScrollViewHLineScroll",
|
||||
CPScrollViewVPageScrollKey = "CPScrollViewVPageScroll",
|
||||
CPScrollViewHPageScrollKey = "CPScrollViewHPageScroll",
|
||||
CPScrollViewHasVScrollerKey = "CPScrollViewHasVScroller",
|
||||
CPScrollViewHasHScrollerKey = "CPScrollViewHasHScroller",
|
||||
CPScrollViewVScrollerKey = "CPScrollViewVScroller",
|
||||
CPScrollViewHScrollerKey = "CPScrollViewHScroller",
|
||||
CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller";
|
||||
var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
||||
CPScrollViewHeaderClipViewKey = "CPScrollViewHeaderClipViewKey",
|
||||
CPScrollViewVLineScrollKey = "CPScrollViewVLineScroll",
|
||||
CPScrollViewHLineScrollKey = "CPScrollViewHLineScroll",
|
||||
CPScrollViewVPageScrollKey = "CPScrollViewVPageScroll",
|
||||
CPScrollViewHPageScrollKey = "CPScrollViewHPageScroll",
|
||||
CPScrollViewHasVScrollerKey = "CPScrollViewHasVScroller",
|
||||
CPScrollViewHasHScrollerKey = "CPScrollViewHasHScroller",
|
||||
CPScrollViewVScrollerKey = "CPScrollViewVScroller",
|
||||
CPScrollViewHScrollerKey = "CPScrollViewHScroller",
|
||||
CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller",
|
||||
CPScrollViewCornerViewKey = "CPScrollViewCornerViewKey";
|
||||
|
||||
@implementation CPScrollView (CPCoding)
|
||||
|
||||
@@ -750,6 +758,7 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
||||
_horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
|
||||
|
||||
_contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
|
||||
_headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey];
|
||||
|
||||
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
|
||||
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
|
||||
@@ -757,7 +766,9 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
||||
_hasVerticalScroller = [aCoder decodeBoolForKey:CPScrollViewHasVScrollerKey];
|
||||
_hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
|
||||
_autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
|
||||
|
||||
|
||||
_cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
|
||||
|
||||
// Do to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state.
|
||||
[[CPRunLoop currentRunLoop] performSelector:@selector(reflectScrolledClipView:) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
|
||||
}
|
||||
@@ -770,7 +781,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey];
|
||||
|
||||
[aCoder encodeObject:_headerClipView forKey:CPScrollViewHeaderClipViewKey];
|
||||
|
||||
[aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey];
|
||||
[aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey];
|
||||
|
||||
@@ -782,6 +794,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
||||
[aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey];
|
||||
[aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey];
|
||||
[aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey];
|
||||
|
||||
[aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey];
|
||||
}
|
||||
|
||||
@end
|
||||
+28
-9
@@ -79,7 +79,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[ nil, nil, nil, nil,
|
||||
return [CPDictionary dictionaryWithObjects:[ [CPNull null], [CPNull null], [CPNull null], [CPNull null],
|
||||
_CGSizeMakeZero(), _CGSizeMakeZero(), _CGInsetMakeZero(), _CGInsetMakeZero(), _CGSizeMakeZero()]
|
||||
forKeys:[ @"knob-slot-color",
|
||||
@"decrement-line-color",
|
||||
@@ -242,14 +242,14 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
{
|
||||
_usableParts = CPNoScrollerParts;
|
||||
|
||||
_partRects[CPScrollerDecrementPage] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerKnob] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerIncrementPage] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerDecrementPage] = CGRectMakeZero();
|
||||
_partRects[CPScrollerKnob] = CGRectMakeZero();
|
||||
_partRects[CPScrollerIncrementPage] = CGRectMakeZero();
|
||||
_partRects[CPScrollerDecrementLine] = CGRectMakeZero();
|
||||
_partRects[CPScrollerIncrementLine] = CGRectMakeZero();
|
||||
|
||||
// In this case, the slot is the entirety of the scroller.
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMakeCopy(bounds);
|
||||
_partRects[CPScrollerKnobSlot] = CGRectMakeCopy(bounds);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -279,9 +279,18 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
_partRects[CPScrollerIncrementPage] = _CGRectMake(0.0, knobLocation + knobHeight, width, height - (knobLocation + knobHeight) - effectiveIncrementLineHeight);
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotHeight);
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
|
||||
|
||||
if(height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
|
||||
_partRects[CPScrollerKnob] = _CGRectMakeZero();
|
||||
|
||||
if(height < decrementLineSize.height + incrementLineSize.height - 2)
|
||||
{
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, 0, width - trackInset.left - trackInset.right, height);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
|
||||
@@ -300,6 +309,16 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotWidth, height - trackInset.top - trackInset.bottom);
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
|
||||
|
||||
if(width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
|
||||
_partRects[CPScrollerKnob] = _CGRectMakeZero();
|
||||
|
||||
if(width < decrementLineSize.width + incrementLineSize.width - 2)
|
||||
{
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(0.0, 0.0, width, slotHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+204
-190
@@ -24,26 +24,10 @@
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
/*!
|
||||
@global
|
||||
@group Menu tags
|
||||
*/
|
||||
CPSearchFieldRecentsTitleMenuItemTag = 1000;
|
||||
/*!
|
||||
@global
|
||||
@group Menu tags
|
||||
*/
|
||||
CPSearchFieldRecentsMenuItemTag = 1001;
|
||||
/*!
|
||||
@global
|
||||
@group Menu tags
|
||||
*/
|
||||
CPSearchFieldClearRecentsMenuItemTag = 1002;
|
||||
/*!
|
||||
@global
|
||||
@group Menu tags
|
||||
*/
|
||||
CPSearchFieldNoRecentsMenuItemTag = 1003;
|
||||
CPSearchFieldRecentsTitleMenuItemTag = 1000;
|
||||
CPSearchFieldRecentsMenuItemTag = 1001;
|
||||
CPSearchFieldClearRecentsMenuItemTag = 1002;
|
||||
CPSearchFieldNoRecentsMenuItemTag = 1003;
|
||||
|
||||
var CPSearchFieldSearchImage = nil,
|
||||
CPSearchFieldFindImage = nil,
|
||||
@@ -79,65 +63,49 @@ var CPSearchFieldSearchImage = nil,
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"]];
|
||||
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"]];
|
||||
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"]];
|
||||
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"]];
|
||||
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:CGSizeMake(25, 22)];
|
||||
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:CGSizeMake(25, 22)];
|
||||
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:CGSizeMake(22, 22)];
|
||||
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:CGSizeMake(22, 22)];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)frame
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil)
|
||||
{
|
||||
_recentSearches = [CPArray array];
|
||||
_maximumRecents = 10;
|
||||
_sendsWholeSearchString = NO;
|
||||
_sendsSearchStringImmediately = NO;
|
||||
|
||||
[self setBezeled:YES];
|
||||
[self setBezelStyle:CPTextFieldRoundedBezel];
|
||||
[self setBordered:YES];
|
||||
[self setEditable:YES];
|
||||
[self setDelegate:self];
|
||||
|
||||
_cancelButton = [[CPButton alloc] initWithFrame:CPMakeRect(frame.size.width - 27,(frame.size.height-22)/2,22,22)];
|
||||
[self resetCancelButton];
|
||||
|
||||
|
||||
[_cancelButton setHidden:YES];
|
||||
[self addSubview:_cancelButton];
|
||||
|
||||
_searchButton = [[CPButton alloc] initWithFrame:CPMakeRect(5,(frame.size.height-25)/2,25,25)];
|
||||
[_searchButton setBezelStyle:CPRegularSquareBezelStyle];
|
||||
[_searchButton setBordered:NO];
|
||||
[_searchButton setImageScaling:CPScaleToFit];
|
||||
if (self = [super initWithFrame:frame])
|
||||
{
|
||||
_recentSearches = [CPArray array];
|
||||
_maximumRecents = 10;
|
||||
_sendsWholeSearchString = NO;
|
||||
_sendsSearchStringImmediately = NO;
|
||||
_recentsAutosaveName = nil;
|
||||
|
||||
[self _initWithFrame:frame];
|
||||
#if PLATFORM(DOM)
|
||||
_cancelButton._DOMElement.style.cursor = "default";
|
||||
_searchButton._DOMElement.style.cursor = "default";
|
||||
#endif
|
||||
|
||||
[self setSearchMenuTemplate:[self _searchMenuTemplate]];
|
||||
[self addSubview:_searchButton];
|
||||
}
|
||||
_cancelButton._DOMElement.style.cursor = "default";
|
||||
_searchButton._DOMElement.style.cursor = "default";
|
||||
#endif
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)copy
|
||||
- (void)_initWithFrame:(CGRect)frame
|
||||
{
|
||||
var copy = [super copy];
|
||||
[self setBezeled:YES];
|
||||
[self setBezelStyle:CPTextFieldRoundedBezel];
|
||||
[self setBordered:YES];
|
||||
[self setEditable:YES];
|
||||
[self setDelegate:self];
|
||||
|
||||
[copy setCancelButton:[_cancelButton copy]];
|
||||
[copy setSearchButton:[_searchButton copy]];
|
||||
[copy setrecentsAutosaveName:[_recentsAutosaveName copy]];
|
||||
[copy setSendsWholeSearchString:[_sendsWholeSearchString copy]];
|
||||
[copy setSendsSearchStringImmediately:[_sendsSearchStringImmediately copy]];
|
||||
[copy setMaximumRecents:_maximumRecents];
|
||||
[copy setSearchMenutemplate:[_searchMenuTemplate copy]];
|
||||
_cancelButton = [[CPButton alloc] initWithFrame:CGRectMake(frame.size.width - 27,(frame.size.height-22)/2,22,22)];
|
||||
[self resetCancelButton];
|
||||
[_cancelButton setHidden:YES];
|
||||
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
|
||||
[self addSubview:_cancelButton];
|
||||
|
||||
return copy;
|
||||
_searchButton = [[CPButton alloc] initWithFrame:CGRectMake(5,(frame.size.height-25)/2,25,25)];
|
||||
[self resetSearchButton];
|
||||
[self addSubview:_searchButton];
|
||||
}
|
||||
|
||||
// Managing Buttons
|
||||
@@ -170,11 +138,11 @@ var CPSearchFieldSearchImage = nil,
|
||||
target,
|
||||
button = [self searchButton];
|
||||
|
||||
if (_searchMenuTemplate == nil)
|
||||
if (_searchMenuTemplate === nil)
|
||||
{
|
||||
searchButtonImage = CPSearchFieldSearchImage;
|
||||
action = [self action];
|
||||
target = [self target];
|
||||
action = @selector(_sendAction:);
|
||||
target = self;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -183,7 +151,10 @@ var CPSearchFieldSearchImage = nil,
|
||||
target = self;
|
||||
}
|
||||
|
||||
[button setBordered:NO];
|
||||
[button setImageScaling:CPScaleToFit];
|
||||
[button setImage:searchButtonImage];
|
||||
[button setAutoresizingMask:CPViewMaxXMargin];
|
||||
[button setTarget:target];
|
||||
[button setAction:action];
|
||||
}
|
||||
@@ -213,11 +184,11 @@ var CPSearchFieldSearchImage = nil,
|
||||
- (void)resetCancelButton
|
||||
{
|
||||
var button = [self cancelButton];
|
||||
[button setBezelStyle:CPRegularSquareBezelStyle];
|
||||
[button setBordered:NO];
|
||||
[button setImageScaling:CPScaleToFit];
|
||||
[button setImage:CPSearchFieldCancelImage];
|
||||
[button setAlternateImage:CPSearchFieldCancelPressedImage];
|
||||
[button setAutoresizingMask:CPViewMinXMargin];
|
||||
[button setTarget:self];
|
||||
[button setAction:@selector(_searchFieldCancel:)];
|
||||
}
|
||||
@@ -253,7 +224,7 @@ var CPSearchFieldSearchImage = nil,
|
||||
@param rect The current bounding rectangle for the search button.
|
||||
Subclasses can override this method to return a new bounding rectangle for the search button. You might use this method to provide a custom layout for the search field control.
|
||||
*/
|
||||
- (CPRect)searchButtonRectForBounds:(CPRect)rect // fix
|
||||
- (CPRect)searchButtonRectForBounds:(CPRect)rect
|
||||
{
|
||||
return [_searchButton frame];
|
||||
}
|
||||
@@ -281,13 +252,14 @@ var CPSearchFieldSearchImage = nil,
|
||||
/*!
|
||||
Sets the menu template object used to dynamically construct the receiver's pop-up icon menu.
|
||||
@param menu The menu template to use.
|
||||
The receiver looks for the tag constants described in ÒMenu tagsÓ to determine how to populate the menu with items related to recent searches. See ÒConfiguring a Search MenuÓ for a sample of how you might set up the search menu template.
|
||||
The receiver looks for the tag constants described in ŇMenu tagsÓ to determine how to populate the menu with items related to recent searches. See ŇConfiguring a Search MenuÓ for a sample of how you might set up the search menu template.
|
||||
*/
|
||||
- (void)setSearchMenuTemplate:(CPMenu)menu
|
||||
{
|
||||
_searchMenuTemplate = menu;
|
||||
|
||||
[self resetSearchButton];
|
||||
[self _loadRecentSearchList];
|
||||
[self _updateSearchMenu];
|
||||
}
|
||||
|
||||
@@ -368,10 +340,10 @@ var CPSearchFieldSearchImage = nil,
|
||||
*/
|
||||
- (void)setRecentSearches:(CPArray)searches
|
||||
{
|
||||
var max = MIN([self maximumRecents],[searches count]);
|
||||
var searches = [searches subarrayWithRange:CPMakeRange(0,max)];
|
||||
_recentSearches = searches;
|
||||
var max = MIN([self maximumRecents], [searches count]),
|
||||
searches = [searches subarrayWithRange:CPMakeRange(0, max)];
|
||||
|
||||
_recentSearches = searches;
|
||||
[self _autosaveRecentSearchList];
|
||||
}
|
||||
|
||||
@@ -390,12 +362,13 @@ var CPSearchFieldSearchImage = nil,
|
||||
*/
|
||||
- (void)setRecentsAutosaveName:(CPString)name
|
||||
{
|
||||
if (_recentsAutosaveName != nil)
|
||||
[self _deregisterForAutosaveNotification];
|
||||
|
||||
_recentsAutosaveName = name;
|
||||
|
||||
if(name != nil)
|
||||
if (_recentsAutosaveName != nil)
|
||||
[self _registerForAutosaveNotification];
|
||||
else
|
||||
[self _deregisterForAutosaveNotification];
|
||||
}
|
||||
|
||||
// Private methods and subclassing
|
||||
@@ -423,95 +396,110 @@ var CPSearchFieldSearchImage = nil,
|
||||
|
||||
- (void)_updateCancelButtonVisibility
|
||||
{
|
||||
[_cancelButton setHidden:([[self stringValue] length] == 0)];
|
||||
[_cancelButton setHidden:([[self stringValue] length] === 0)];
|
||||
}
|
||||
|
||||
- (void)controlTextDidChange:(CPNotification)aNotification
|
||||
{
|
||||
if(!_sendsWholeSearchString)
|
||||
if (![self sendsWholeSearchString])
|
||||
{
|
||||
if(_sendsSearchStringImmediately)
|
||||
if ([self sendsSearchStringImmediately])
|
||||
[self _sendPartialString];
|
||||
else
|
||||
{
|
||||
[_partialStringTimer invalidate];
|
||||
var timeInterval = [CPSearchField _keyboardDelayForPartialSearchString:[self stringValue]];
|
||||
|
||||
_partialStringTimer = [CPTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:@selector(_sendPartialString) userInfo:nil repeats:NO];
|
||||
_partialStringTimer = [CPTimer scheduledTimerWithTimeInterval:timeInterval
|
||||
target:self
|
||||
selector:@selector(_sendPartialString)
|
||||
userInfo:nil
|
||||
repeats:NO];
|
||||
}
|
||||
}
|
||||
|
||||
[self _updateCancelButtonVisibility];
|
||||
}
|
||||
|
||||
- (void)_sendAction:(id)sender
|
||||
{
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
[super sendAction:anAction to:anObject];
|
||||
|
||||
[_partialStringTimer invalidate];
|
||||
|
||||
var current_value = [self objectValue];
|
||||
if(current_value != nil && current_value != "" && ![_recentSearches containsObject:current_value])
|
||||
{
|
||||
[self _addStringToRecentSearches:current_value];
|
||||
[self _updateSearchMenu];
|
||||
}
|
||||
|
||||
[self _addStringToRecentSearches:[self stringValue]];
|
||||
[self _updateCancelButtonVisibility];
|
||||
}
|
||||
|
||||
- (void)_addStringToRecentSearches:(CPString)string
|
||||
{
|
||||
var newSearches = [CPMutableArray arrayWithArray:_recentSearches];
|
||||
[newSearches addObject:string];
|
||||
[self setRecentSearches:newSearches];
|
||||
if (string === nil || string === @"" || [_recentSearches containsObject:string])
|
||||
return;
|
||||
|
||||
var searches = [CPMutableArray arrayWithArray:_recentSearches];
|
||||
[searches addObject:string];
|
||||
[self setRecentSearches:searches];
|
||||
[self _updateSearchMenu];
|
||||
}
|
||||
|
||||
- (BOOL)trackMouse:(CPEvent)event
|
||||
{
|
||||
var rect;
|
||||
var point;
|
||||
var location = [event locationInWindow];
|
||||
var rect,
|
||||
point,
|
||||
location = [event locationInWindow];
|
||||
|
||||
point = [self convertPoint:location fromView:nil];
|
||||
|
||||
rect = [self searchButtonRectForBounds:[self frame]];
|
||||
|
||||
if (CPRectContainsPoint(rect,point))
|
||||
{
|
||||
return [[self searchButton] trackMouse:event];
|
||||
}
|
||||
{
|
||||
return [[self searchButton] trackMouse:event];
|
||||
}
|
||||
|
||||
rect = [self cancelButtonRectForBounds:[self frame]];
|
||||
if (CPRectContainsPoint(rect,point))
|
||||
{
|
||||
return [[self cancelButton] trackMouse:event];
|
||||
}
|
||||
{
|
||||
return [[self cancelButton] trackMouse:event];
|
||||
}
|
||||
|
||||
return [super trackMouse:event];
|
||||
}
|
||||
|
||||
- (CPMenu)_searchMenuTemplate
|
||||
- (CPMenu)_defaultSearchMenuTemplate
|
||||
{
|
||||
var template, item;
|
||||
|
||||
template = [[CPMenu alloc] init];
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Recent searches" action:NULL keyEquivalent:@""];
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Recent searches"
|
||||
action:NULL
|
||||
keyEquivalent:@""];
|
||||
[item setTag:CPSearchFieldRecentsTitleMenuItemTag];
|
||||
[item setEnabled:NO];
|
||||
[template addItem:item];
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Recent search item" action:@selector(_searchFieldSearch:) keyEquivalent:@""];
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Recent search item"
|
||||
action:@selector(_searchFieldSearch:)
|
||||
keyEquivalent:@""];
|
||||
[item setTag:CPSearchFieldRecentsMenuItemTag];
|
||||
[item setTarget:self];
|
||||
[template addItem:item];
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Clear recent searches" action:@selector(_searchFieldClearRecents:) keyEquivalent:@""];
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Clear recent searches"
|
||||
action:@selector(_searchFieldClearRecents:)
|
||||
keyEquivalent:@""];
|
||||
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
|
||||
[item setTarget:self];
|
||||
[template addItem:item];
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"No recent searches" action:NULL keyEquivalent:@""];
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"No recent searches"
|
||||
action:NULL
|
||||
keyEquivalent:@""];
|
||||
[item setTag:CPSearchFieldNoRecentsMenuItemTag];
|
||||
[item setEnabled:NO];
|
||||
[template addItem:item];
|
||||
@@ -521,41 +509,56 @@ var CPSearchFieldSearchImage = nil,
|
||||
|
||||
- (void)_updateSearchMenu
|
||||
{
|
||||
if(_searchMenuTemplate == nil)
|
||||
if (_searchMenuTemplate === nil)
|
||||
return;
|
||||
|
||||
var i, menu = [[CPMenu alloc] init];
|
||||
var countOfRecents = [_recentSearches count];
|
||||
var i, menu = [[CPMenu alloc] init],
|
||||
countOfRecents = [_recentSearches count],
|
||||
numberOfItems = [_searchMenuTemplate numberOfItems];
|
||||
|
||||
for (i = 0; i < [_searchMenuTemplate numberOfItems]; i++)
|
||||
for (i = 0; i < numberOfItems; i++)
|
||||
{
|
||||
var item = [_searchMenuTemplate itemAtIndex:i];
|
||||
var tag = [item tag];
|
||||
var item = [_searchMenuTemplate itemAtIndex:i],
|
||||
tag = [item tag];
|
||||
|
||||
if(tag == CPSearchFieldClearRecentsMenuItemTag && countOfRecents != 0)
|
||||
if (!(tag === CPSearchFieldRecentsTitleMenuItemTag && countOfRecents === 0) &&
|
||||
!(tag === CPSearchFieldClearRecentsMenuItemTag && countOfRecents === 0) &&
|
||||
!(tag === CPSearchFieldNoRecentsMenuItemTag && countOfRecents != 0) &&
|
||||
!(tag === CPSearchFieldRecentsMenuItemTag))
|
||||
{
|
||||
var separator = [CPMenuItem separatorItem];
|
||||
[menu addItem:separator];
|
||||
}
|
||||
var itemAction, itemTarget;
|
||||
switch (tag)
|
||||
{
|
||||
case CPSearchFieldRecentsTitleMenuItemTag : itemAction = NULL; itemTarget = NULL; break;
|
||||
case CPSearchFieldClearRecentsMenuItemTag : itemAction = @selector(_searchFieldClearRecents:); itemTarget = self; break;
|
||||
case CPSearchFieldNoRecentsMenuItemTag : itemAction = NULL; itemTarget = NULL; break;
|
||||
default: itemAction = [item action]; itemTarget = [item target]; break;
|
||||
}
|
||||
|
||||
if (tag === CPSearchFieldClearRecentsMenuItemTag || tag === CPSearchFieldRecentsTitleMenuItemTag)
|
||||
{
|
||||
var separator = [CPMenuItem separatorItem];
|
||||
[separator setEnabled:NO];
|
||||
[menu addItem:separator];
|
||||
}
|
||||
|
||||
if (!(tag == CPSearchFieldRecentsTitleMenuItemTag && countOfRecents == 0) &&
|
||||
!(tag == CPSearchFieldClearRecentsMenuItemTag && countOfRecents == 0) &&
|
||||
!(tag == CPSearchFieldNoRecentsMenuItemTag && countOfRecents != 0) &&
|
||||
!(tag == CPSearchFieldRecentsMenuItemTag))
|
||||
{
|
||||
var templateItem = [[CPMenuItem alloc] initWithTitle:[item title] action:[item action] keyEquivalent:[item keyEquivalent]];
|
||||
[templateItem setTarget:[item target]];
|
||||
[templateItem setEnabled:[item isEnabled]];
|
||||
[templateItem setTag:[item tag]];
|
||||
var templateItem = [[CPMenuItem alloc] initWithTitle:[item title]
|
||||
action:itemAction
|
||||
keyEquivalent:[item keyEquivalent]];
|
||||
[templateItem setTarget:itemTarget];
|
||||
[templateItem setEnabled:([item isEnabled] && itemAction != NULL)];
|
||||
[templateItem setTag:tag];
|
||||
[menu addItem:templateItem];
|
||||
}
|
||||
else if (tag == CPSearchFieldRecentsMenuItemTag)
|
||||
else if (tag === CPSearchFieldRecentsMenuItemTag)
|
||||
{
|
||||
var j;
|
||||
for (j = 0; j < countOfRecents; j++)
|
||||
{
|
||||
var rencentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j] action:[item action] keyEquivalent:[item keyEquivalent]];
|
||||
[rencentItem setTarget:[item target]];
|
||||
var rencentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j]
|
||||
action:@selector(_searchFieldSearch:)
|
||||
keyEquivalent:[item keyEquivalent]];
|
||||
[rencentItem setTarget:self];
|
||||
[menu addItem:rencentItem];
|
||||
}
|
||||
}
|
||||
@@ -563,16 +566,15 @@ var CPSearchFieldSearchImage = nil,
|
||||
_searchMenu = menu;
|
||||
}
|
||||
|
||||
|
||||
- (void)_showMenu:(id)sender
|
||||
{
|
||||
if(_searchMenu == nil || ![self isEnabled])
|
||||
if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled])
|
||||
return;
|
||||
|
||||
[super selectText:nil];
|
||||
var aFrame = [[self superview] convertRect:[self frame] toView:nil],
|
||||
location = CPMakePoint(aFrame.origin.x + 10, aFrame.origin.y + aFrame.size.height - 4);
|
||||
|
||||
var origin = CPMakePoint([self frame].origin.x, [self frame].origin.y + [self frame].size.height);
|
||||
var anEvent = [CPEvent keyEventWithType:CPRightMouseDown location:origin modifierFlags:0 timestamp:[CPDate date] windowNumber:1 context:[[CPGraphicsContext currentContext] graphicsPort] characters:"" charactersIgnoringModifiers:"" isARepeat:NO keyCode:0];
|
||||
var anEvent = [CPEvent mouseEventWithType:CPRightMouseDown location:location modifierFlags:0 timestamp:[[CPApp currentEvent] timestamp] windowNumber:[[self window] windowNumber] context:nil eventNumber:1 clickCount:1 pressure:0];
|
||||
|
||||
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:sender];
|
||||
}
|
||||
@@ -584,16 +586,21 @@ var CPSearchFieldSearchImage = nil,
|
||||
|
||||
- (void)_searchFieldCancel:(id)sender
|
||||
{
|
||||
[self setObjectValue:nil];
|
||||
[self setObjectValue:@""];
|
||||
[self _sendPartialString];
|
||||
[self _updateCancelButtonVisibility];
|
||||
[sender setHidden:YES];
|
||||
}
|
||||
|
||||
- (void)_searchFieldSearch:(id)sender
|
||||
{
|
||||
[self setObjectValue:[sender title]];
|
||||
var searchString = [sender title];
|
||||
|
||||
if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
|
||||
[self _addStringToRecentSearches:searchString];
|
||||
|
||||
[self setObjectValue:searchString];
|
||||
[self _sendPartialString];
|
||||
|
||||
[self _updateCancelButtonVisibility];
|
||||
}
|
||||
|
||||
@@ -613,57 +620,51 @@ var CPSearchFieldSearchImage = nil,
|
||||
[[CPNotificationCenter defaultCenter] removeObserver:self name:@"CPAutosavedRecentsChangedNotification" object:nil];
|
||||
}
|
||||
|
||||
- (void)_updateAutosavedRecents:(id)notification
|
||||
{
|
||||
var name = [notification object];
|
||||
var list = [self recentSearches];
|
||||
|
||||
[[CPUserDefaults standardUserDefaults] setObject:list forKey:name];
|
||||
|
||||
}
|
||||
|
||||
- (void)_autosaveRecentSearchList
|
||||
{
|
||||
if(_recentsAutosaveName != nil)
|
||||
if (_recentsAutosaveName != nil)
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:@"CPAutosavedRecentsChangedNotification" object:_recentsAutosaveName];
|
||||
}
|
||||
|
||||
- (void)_updateAutosavedRecents:(id)notification
|
||||
{
|
||||
var list = [self recentSearches],
|
||||
name = [notification object],
|
||||
bundle_name = [[[CPBundle mainBundle] infoDictionary] objectForKey:"CPBundleName"],
|
||||
cookie_name = [bundle_name lowercaseString] + "." + [notification object],
|
||||
|
||||
cookie = [[CPCookie alloc] initWithName:cookie_name],
|
||||
cookie_value = [list componentsJoinedByString:@","];
|
||||
|
||||
[cookie setValue:cookie_value
|
||||
expires:[[CPDate alloc] initWithTimeIntervalSinceNow:3600*24*365]
|
||||
domain:(window.location.href.hostname)];
|
||||
}
|
||||
|
||||
- (void)_loadRecentSearchList
|
||||
{
|
||||
var list,
|
||||
name = [self recentsAutosaveName];
|
||||
|
||||
list = [[CPUserDefaults standardUserDefaults] objectForKey:name];
|
||||
_recentSearches = list;
|
||||
}
|
||||
if (name === nil)
|
||||
return;
|
||||
|
||||
/*
|
||||
- (BOOL)trackMouse:(CPEvent)theEvent inRect:(CPRect)cellFrame ofView:(CPView)aTextView untilMouseUp:(BOOL)flag
|
||||
{
|
||||
}
|
||||
var bundle_name = [[[CPBundle mainBundle] infoDictionary] objectForKey:"CPBundleName"],
|
||||
cookie_name = [bundle_name lowercaseString] + "." + name,
|
||||
|
||||
- (BOOL)_trimRecentSearchList
|
||||
{
|
||||
}
|
||||
cookie = [[CPCookie alloc] initWithName:cookie_name];
|
||||
|
||||
- (void)_trackButton:(CPButton)button forEvent:(CPEvent)event inRect:(CPRect)rect ofView:(id)view
|
||||
{
|
||||
if (cookie != nil)
|
||||
{
|
||||
var cookie_value = [cookie value];
|
||||
list = (cookie_value != @"") ? [cookie_value componentsSeparatedByString:@","] : [CPArray array];
|
||||
_recentSearches = list;
|
||||
}
|
||||
}
|
||||
|
||||
- (id)_selectOrEdit:(CPRect)rect inView:(id)view target:(id)target editor:(id)editor event:(id)event start:(int)start end:(int)end
|
||||
{
|
||||
}
|
||||
|
||||
- (void)resetCursorRect:(CPRect)rect inView:(id)view
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
@end
|
||||
|
||||
var CPSearchButtonKey = @"CPSearchButtonKey",
|
||||
CPCancelButtonKey = @"CPCancelButtonKey",
|
||||
CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
||||
var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
||||
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
|
||||
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
|
||||
CPMaximumRecentsKey = @"CPMaximumRecentsKey",
|
||||
@@ -673,32 +674,45 @@ var CPSearchButtonKey = @"CPSearchButtonKey",
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)coder
|
||||
{
|
||||
[super encodeWithCoder:coder];
|
||||
|
||||
[coder encodeObject:_searchButton forKey:CPSearchButtonKey];
|
||||
[coder encodeObject:_cancelButton forKey:CPCancelButtonKey];
|
||||
[coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
|
||||
[_searchButton removeFromSuperview];
|
||||
[_cancelButton removeFromSuperview];
|
||||
|
||||
[super encodeWithCoder:coder];
|
||||
|
||||
if (_searchButton)
|
||||
[self addSubview:_searchButton];
|
||||
if (_cancelButton)
|
||||
[self addSubview:_cancelButton];
|
||||
|
||||
[coder encodeBool:_sendsWholeSearchString forKey:CPSendsWholeSearchStringKey];
|
||||
[coder encodeBool:_sendsSearchStringImmediately forKey:CPSendsSearchStringImmediatelyKey];
|
||||
[coder encodeInt:_maximumRecents forKey:CPMaximumRecentsKey];
|
||||
[coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
|
||||
|
||||
if (_recentsAutosaveName)
|
||||
[coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
|
||||
if (_searchMenuTemplate)
|
||||
[coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)coder
|
||||
{
|
||||
self = [super initWithCoder:coder];
|
||||
|
||||
_searchButton = [coder decodeObjectForKey:CPSearchButtonKey];
|
||||
_cancelButton = [coder decodeObjectForKey:CPCancelButtonKey];
|
||||
_recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey];
|
||||
_sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
|
||||
_sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
|
||||
_maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey];
|
||||
[self setSearchMenuTemplate:[coder decodeObjectForKey:CPSearchMenuTemplateKey]];
|
||||
[self resetCancelButton];
|
||||
[self setDelegate:self];
|
||||
if (self = [super initWithCoder:coder])
|
||||
{
|
||||
[self _initWithFrame:[self frame]];
|
||||
|
||||
_recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey];
|
||||
_sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
|
||||
_sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
|
||||
_maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey];
|
||||
|
||||
var template = [coder decodeObjectForKey:CPSearchMenuTemplateKey];
|
||||
if (template)
|
||||
[self setSearchMenuTemplate:template];
|
||||
|
||||
[self setDelegate:self];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
+43
-35
@@ -26,20 +26,8 @@
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
/*
|
||||
@global
|
||||
@group CPSegmentSwitchTracking
|
||||
*/
|
||||
CPSegmentSwitchTrackingSelectOne = 0;
|
||||
/*
|
||||
@global
|
||||
@group CPSegmentSwitchTracking
|
||||
*/
|
||||
CPSegmentSwitchTrackingSelectAny = 1;
|
||||
/*
|
||||
@global
|
||||
@group CPSegmentSwitchTracking
|
||||
*/
|
||||
CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
/*!
|
||||
@@ -68,7 +56,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[CPCenterTextAlignment, CPCenterVerticalTextAlignment, CPImageLeft, CPScaleNone, _CGInsetMakeZero(), _CGInsetMakeZero(), nil, nil, nil, nil, 1.0, 24.0]
|
||||
return [CPDictionary dictionaryWithObjects:[CPCenterTextAlignment, CPCenterVerticalTextAlignment, CPImageLeft, CPScaleNone, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], [CPNull null], 1.0, 24.0]
|
||||
forKeys:[@"alignment", @"vertical-alignment", @"image-position", @"image-scaling", @"bezel-inset", @"content-inset", @"left-segment-bezel-color", @"right-segment-bezel-color", @"center-segment-bezel-color", @"divider-bezel-color", @"divider-thickness", @"default-height"]];
|
||||
}
|
||||
|
||||
@@ -375,7 +363,10 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
|
||||
{
|
||||
_segments[aSegment].enabled = isEnabled;
|
||||
if (isEnabled)
|
||||
_themeStates[aSegment] &= ~CPThemeStateDisabled;
|
||||
else
|
||||
_themeStates[aSegment] |= CPThemeStateDisabled;
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
@@ -388,7 +379,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (BOOL)isEnabledForSegment:(unsigned)aSegment
|
||||
{
|
||||
return _segments[aSegment].enabled;
|
||||
return !(_themeStates[aSegment] & CPThemeStateDisabled)
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -462,30 +453,28 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
}
|
||||
else if (aName === "right-segment-bezel")
|
||||
{
|
||||
var lastSegmentLeftOffset = [self _leftOffsetForSegment:[self _indexOfLastSegment]];
|
||||
|
||||
return CPRectMake(lastSegmentLeftOffset + [self widthForSegment:[self _indexOfLastSegment]] - contentInset.right,
|
||||
return CPRectMake(CGRectGetWidth([self bounds]) - contentInset.right,
|
||||
bezelInset.top,
|
||||
contentInset.right,
|
||||
height);
|
||||
}
|
||||
else if (aName.substring(0, "segment-bezel".length) == "segment-bezel")
|
||||
else if (aName.indexOf("segment-bezel") === 0)
|
||||
{
|
||||
var segment = parseInt(aName.substring("segment-bezel-".length), 10),
|
||||
frame = CGRectCreateCopy(_segments[segment].frame);
|
||||
|
||||
if (segment == 0)
|
||||
if (segment === 0)
|
||||
{
|
||||
frame.origin.x += contentInset.left;
|
||||
frame.size.width -= contentInset.left;
|
||||
}
|
||||
|
||||
if (segment == _segments.length - 1)
|
||||
frame.size.width -= contentInset.right;
|
||||
if (segment === _segments.length - 1)
|
||||
frame.size.width = CGRectGetWidth([self bounds]) - contentInset.right - frame.origin.x;
|
||||
|
||||
return frame;
|
||||
}
|
||||
else if (aName.substring(0, "divider-bezel".length) == "divider-bezel")
|
||||
else if (aName.indexOf("divider-bezel") === 0)
|
||||
{
|
||||
var segment = parseInt(aName.substring("divider-bezel-".length), 10),
|
||||
width = [self widthForSegment:segment],
|
||||
@@ -494,7 +483,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
return CGRectMake(left + width, bezelInset.top, thickness, height);
|
||||
}
|
||||
else if (aName.substring(0, "segment-content".length) == "segment-content")
|
||||
else if (aName.indexOf("segment-content") === 0)
|
||||
{
|
||||
var segment = parseInt(aName.substring("segment-content-".length), 10);
|
||||
|
||||
@@ -517,8 +506,12 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
if (_segments.length <= 0)
|
||||
return;
|
||||
|
||||
var themeState = _themeStates[0];
|
||||
|
||||
themeState |= _themeState & CPThemeStateDisabled;
|
||||
|
||||
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
|
||||
inState:_themeStates[0]];
|
||||
inState:themeState];
|
||||
|
||||
var leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
|
||||
positioned:CPWindowBelow
|
||||
@@ -526,8 +519,12 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
[leftBezelView setBackgroundColor:leftCapColor];
|
||||
|
||||
var themeState = _themeStates[_themeStates.length - 1];
|
||||
|
||||
themeState |= _themeState & CPThemeStateDisabled;
|
||||
|
||||
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
|
||||
inState:_themeStates[_themeStates.length - 1]];
|
||||
inState:themeState];
|
||||
|
||||
var rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
|
||||
positioned:CPWindowBelow
|
||||
@@ -703,7 +700,16 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
while (count--)
|
||||
if (CGRectContainsPoint(_segments[count].frame, aPoint))
|
||||
return count;
|
||||
|
||||
|
||||
if (_segments.length)
|
||||
{
|
||||
var adjustedLastFrame = CGRectCreateCopy(_segments[_segments.length - 1].frame);
|
||||
adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x;
|
||||
|
||||
if (CGRectContainsPoint(adjustedLastFrame, aPoint))
|
||||
return _segments.length - 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -734,7 +740,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
if (_trackingSegment == -1)
|
||||
return;
|
||||
|
||||
if (CGRectContainsPoint(_segments[_trackingSegment].frame, location))
|
||||
if (_trackingSegment === [self testSegment:location])
|
||||
{
|
||||
if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
|
||||
{
|
||||
@@ -765,10 +771,13 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
if (type == CPLeftMouseDown)
|
||||
{
|
||||
_trackingHighlighted = YES;
|
||||
_trackingSegment = [self testSegment:location];
|
||||
|
||||
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
||||
var trackingSegment = [self testSegment:location];
|
||||
if (trackingSegment > -1 && [self isEnabledForSegment:trackingSegment])
|
||||
{
|
||||
_trackingHighlighted = YES;
|
||||
_trackingSegment = trackingSegment;
|
||||
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
||||
}
|
||||
}
|
||||
|
||||
else if (type == CPLeftMouseDragged)
|
||||
@@ -776,12 +785,11 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
if (_trackingSegment == -1)
|
||||
return;
|
||||
|
||||
var highlighted = CGRectContainsPoint(_segments[_trackingSegment].frame, location);
|
||||
|
||||
var highlighted = [self testSegment:location] === _trackingSegment;
|
||||
if (highlighted != _trackingHighlighted)
|
||||
{
|
||||
_trackingHighlighted = highlighted;
|
||||
|
||||
|
||||
[self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ CPCircularSlider = 1;
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[nil, _CGSizeMakeZero(), 0.0, nil]
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], _CGSizeMakeZero(), 0.0, [CPNull null]]
|
||||
forKeys:[@"knob-color", @"knob-size", @"track-width", @"track-color"]];
|
||||
}
|
||||
|
||||
|
||||
@@ -45,14 +45,16 @@
|
||||
CPTextField _saturationLabel;
|
||||
CPTextField _brightnessLabel;
|
||||
CPTextField _hexLabel;
|
||||
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
DOMElement _redValue;
|
||||
DOMElement _greenValue;
|
||||
DOMElement _blueValue;
|
||||
DOMElement _hueValue;
|
||||
DOMElement _saturationValue;
|
||||
DOMElement _brightnessValue;
|
||||
DOMElement _hexValue;
|
||||
DOMElement _hexValue;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
|
||||
@@ -81,7 +83,8 @@
|
||||
[_redSlider setTarget: self];
|
||||
[_redSlider setAction: @selector(sliderChanged:)];
|
||||
[_redSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
var updateFunction = function(aDOMEvent)
|
||||
{
|
||||
if(isNaN(this.value))
|
||||
@@ -147,6 +150,7 @@
|
||||
|
||||
redValue._DOMElement.appendChild(_redValue);
|
||||
[_contentView addSubview: redValue];
|
||||
#endif
|
||||
|
||||
_greenLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 58, 15, 20)];
|
||||
[_greenLabel setStringValue: "G"];
|
||||
@@ -159,6 +163,7 @@
|
||||
[_greenSlider setAction: @selector(sliderChanged:)];
|
||||
[_greenSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//green value input box
|
||||
var greenValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 58, 45, 20)];
|
||||
[greenValue setAutoresizingMask: CPViewMinXMargin];
|
||||
@@ -168,6 +173,7 @@
|
||||
|
||||
greenValue._DOMElement.appendChild(_greenValue);
|
||||
[_contentView addSubview: greenValue];
|
||||
#endif
|
||||
|
||||
_blueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 81, 15, 20)];
|
||||
[_blueLabel setStringValue: "B"];
|
||||
@@ -180,6 +186,7 @@
|
||||
[_blueSlider setAction: @selector(sliderChanged:)];
|
||||
[_blueSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//blue value input box
|
||||
var blueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 81, 45, 20)];
|
||||
[blueValue setAutoresizingMask: CPViewMinXMargin];
|
||||
@@ -189,7 +196,7 @@
|
||||
|
||||
blueValue._DOMElement.appendChild(_blueValue);
|
||||
[_contentView addSubview: blueValue];
|
||||
|
||||
#endif
|
||||
_hsbLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 120, 190, 20)];
|
||||
[_hsbLabel setStringValue: "Hue, Saturation, Brightness"];
|
||||
[_hsbLabel setTextColor:[CPColor blackColor]];
|
||||
@@ -205,6 +212,7 @@
|
||||
[_hueSlider setAction: @selector(sliderChanged:)];
|
||||
[_hueSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//red value input box
|
||||
var hueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 145, 45, 20)];
|
||||
[hueValue setAutoresizingMask: CPViewMinXMargin];
|
||||
@@ -214,7 +222,7 @@
|
||||
|
||||
hueValue._DOMElement.appendChild(_hueValue);
|
||||
[_contentView addSubview: hueValue];
|
||||
|
||||
#endif
|
||||
_saturationLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 168, 15, 20)];
|
||||
[_saturationLabel setStringValue: "S"];
|
||||
[_saturationLabel setTextColor:[CPColor blackColor]];
|
||||
@@ -226,6 +234,7 @@
|
||||
[_saturationSlider setAction: @selector(sliderChanged:)];
|
||||
[_saturationSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//green value input box
|
||||
var saturationValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 168, 45, 20)];
|
||||
[saturationValue setAutoresizingMask: CPViewMinXMargin];
|
||||
@@ -235,7 +244,7 @@
|
||||
|
||||
saturationValue._DOMElement.appendChild(_saturationValue);
|
||||
[_contentView addSubview: saturationValue];
|
||||
|
||||
#endif
|
||||
_brightnessLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 191, 15, 20)];
|
||||
[_brightnessLabel setStringValue: "B"];
|
||||
[_brightnessLabel setTextColor:[CPColor blackColor]];
|
||||
@@ -247,6 +256,7 @@
|
||||
[_brightnessSlider setAction: @selector(sliderChanged:)];
|
||||
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//blue value input box
|
||||
var brightnessValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 191, 45, 20)];
|
||||
[brightnessValue setAutoresizingMask: CPViewMinXMargin];
|
||||
@@ -256,11 +266,12 @@
|
||||
|
||||
brightnessValue._DOMElement.appendChild(_brightnessValue);
|
||||
[_contentView addSubview: brightnessValue];
|
||||
|
||||
#endif
|
||||
_hexLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 230, 30, 20)];
|
||||
[_hexLabel setStringValue: "Hex"];
|
||||
[_hexLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//hex input box
|
||||
_hexValue = _redValue.cloneNode(false);
|
||||
_hexValue.style.top = "228px";
|
||||
@@ -289,7 +300,8 @@
|
||||
};
|
||||
|
||||
_contentView._DOMElement.appendChild(_hexValue);
|
||||
|
||||
#endif
|
||||
|
||||
[_contentView addSubview: _rgbLabel];
|
||||
[_contentView addSubview: _redLabel];
|
||||
[_contentView addSubview: _greenLabel];
|
||||
@@ -380,7 +392,9 @@
|
||||
|
||||
- (void)updateHex:(CPColor)aColor
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_hexValue.value = [aColor hexString];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)updateRGBSliders:(CPColor)aColor
|
||||
@@ -394,6 +408,7 @@
|
||||
|
||||
- (void)updateLabels
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_hueValue.value = ROUND([_hueSlider floatValue]);
|
||||
_saturationValue.value = ROUND([_saturationSlider floatValue]);
|
||||
_brightnessValue.value = ROUND([_brightnessSlider floatValue]);
|
||||
@@ -401,6 +416,7 @@
|
||||
_redValue.value = ROUND([_redSlider floatValue] * 255);
|
||||
_greenValue.value = ROUND([_greenSlider floatValue] * 255);
|
||||
_blueValue.value = ROUND([_blueSlider floatValue] * 255);
|
||||
#endif
|
||||
}
|
||||
|
||||
- (CPImage)provideNewButtonImage
|
||||
|
||||
+233
-90
@@ -20,6 +20,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPButtonBar.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPView.j"
|
||||
|
||||
@@ -43,18 +44,20 @@ var CPSplitViewHorizontalImage = nil,
|
||||
id _delegate;
|
||||
BOOL _isVertical;
|
||||
BOOL _isPaneSplitter;
|
||||
|
||||
|
||||
int _currentDivider;
|
||||
float _initialOffset;
|
||||
|
||||
|
||||
CPString _originComponent;
|
||||
CPString _sizeComponent;
|
||||
|
||||
|
||||
CPArray _DOMDividerElements;
|
||||
CPString _dividerImagePath;
|
||||
int _drawingDivider;
|
||||
|
||||
|
||||
BOOL _needsResizeSubviews;
|
||||
|
||||
CPArray _buttonBars;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -75,12 +78,13 @@ var CPSplitViewHorizontalImage = nil,
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_currentDivider = CPNotFound;
|
||||
|
||||
|
||||
_DOMDividerElements = [];
|
||||
|
||||
_buttonBars = [];
|
||||
|
||||
[self _setVertical:YES];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -98,13 +102,13 @@ var CPSplitViewHorizontalImage = nil,
|
||||
{
|
||||
if (![self _setVertical:shouldBeVertical])
|
||||
return;
|
||||
|
||||
|
||||
// Just re-adjust evenly.
|
||||
var frame = [self frame],
|
||||
dividerThickness = [self dividerThickness];
|
||||
|
||||
|
||||
[self _postNotificationWillResize];
|
||||
|
||||
|
||||
var eachSize = ROUND((frame.size[_sizeComponent] - dividerThickness * (_subviews.length - 1)) / _subviews.length),
|
||||
index = 0,
|
||||
count = _subviews.length;
|
||||
@@ -115,9 +119,9 @@ var CPSplitViewHorizontalImage = nil,
|
||||
else
|
||||
for (; index < count; ++index)
|
||||
[_subviews[index] setFrame:CGRectMake(0, ROUND((eachSize + dividerThickness) * index), frame.size.width, eachSize)];
|
||||
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
|
||||
[self _postNotificationDidResize];
|
||||
|
||||
}
|
||||
@@ -125,13 +129,13 @@ var CPSplitViewHorizontalImage = nil,
|
||||
- (BOOL)_setVertical:(BOOL)shouldBeVertical
|
||||
{
|
||||
var changed = (_isVertical != shouldBeVertical);
|
||||
|
||||
|
||||
_isVertical = shouldBeVertical;
|
||||
|
||||
|
||||
_originComponent = [self isVertical] ? "x" : "y";
|
||||
_sizeComponent = [self isVertical] ? "width" : "height";
|
||||
_dividerImagePath = [self isVertical] ? [CPSplitViewVerticalImage filename] : [CPSplitViewHorizontalImage filename];
|
||||
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -144,20 +148,21 @@ var CPSplitViewHorizontalImage = nil,
|
||||
{
|
||||
if (_isPaneSplitter == shouldBePaneSplitter)
|
||||
return;
|
||||
|
||||
|
||||
_isPaneSplitter = shouldBePaneSplitter;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_DOMDividerElements = [];
|
||||
#endif
|
||||
if(_DOMDividerElements[_drawingDivider])
|
||||
[self _setupDOMDivider]
|
||||
|
||||
// The divider changes size when pane splitter mode is toggled, so the
|
||||
// subviews need to change size too.
|
||||
_needsResizeSubviews = YES;
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)didAddSubview:(CPView)aSubview
|
||||
{
|
||||
_needsResizeSubviews = YES;
|
||||
// [self adjustSubviews];
|
||||
}
|
||||
|
||||
- (BOOL)isSubviewCollapsed:(CPView)subview
|
||||
@@ -169,9 +174,9 @@ var CPSplitViewHorizontalImage = nil,
|
||||
{
|
||||
var frame = [_subviews[aDivider] frame],
|
||||
rect = CGRectMakeZero();
|
||||
|
||||
|
||||
rect.size = [self frame].size;
|
||||
|
||||
|
||||
rect.size[_sizeComponent] = [self dividerThickness];
|
||||
rect.origin[_originComponent] = frame.origin[_originComponent] + frame.size[_sizeComponent];
|
||||
|
||||
@@ -181,19 +186,19 @@ var CPSplitViewHorizontalImage = nil,
|
||||
- (CGRect)effectiveRectOfDividerAtIndex:(int)aDivider
|
||||
{
|
||||
var realRect = [self rectOfDividerAtIndex:aDivider];
|
||||
|
||||
|
||||
var padding = 2;
|
||||
|
||||
|
||||
realRect.size[_sizeComponent] += padding * 2;
|
||||
realRect.origin[_originComponent] -= padding;
|
||||
|
||||
|
||||
return realRect;
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
var count = [_subviews count] - 1;
|
||||
|
||||
|
||||
while ((count--) > 0)
|
||||
{
|
||||
_drawingDivider = count;
|
||||
@@ -207,29 +212,34 @@ var CPSplitViewHorizontalImage = nil,
|
||||
if (!_DOMDividerElements[_drawingDivider])
|
||||
{
|
||||
_DOMDividerElements[_drawingDivider] = document.createElement("div");
|
||||
_DOMDividerElements[_drawingDivider].style.cursor = "move";
|
||||
|
||||
_DOMDividerElements[_drawingDivider].style.position = "absolute";
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundRepeat = "repeat";
|
||||
|
||||
CPDOMDisplayServerAppendChild(_DOMElement, _DOMDividerElements[_drawingDivider]);
|
||||
|
||||
if (_isPaneSplitter)
|
||||
{
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundColor = "#A5A5A5";
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundColor = "";
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundImage = "url('"+_dividerImagePath+"')";
|
||||
}
|
||||
}
|
||||
[self _setupDOMDivider];
|
||||
}
|
||||
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect));
|
||||
CPDOMDisplayServerSetStyleSize(_DOMDividerElements[_drawingDivider], _CGRectGetWidth(aRect), _CGRectGetHeight(aRect));
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)_setupDOMDivider
|
||||
{
|
||||
if (_isPaneSplitter)
|
||||
{
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundColor = "#A5A5A5";
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundColor = "";
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundImage = "url('"+_dividerImagePath+"')";
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewWillDraw
|
||||
{
|
||||
[self _adjustSubviewsWithCalculatedSize];
|
||||
@@ -239,13 +249,13 @@ var CPSplitViewHorizontalImage = nil,
|
||||
{
|
||||
if (!_needsResizeSubviews)
|
||||
return;
|
||||
|
||||
|
||||
_needsResizeSubviews = NO;
|
||||
|
||||
|
||||
var subviews = [self subviews],
|
||||
count = subviews.length,
|
||||
oldSize = CGSizeMakeZero();
|
||||
|
||||
|
||||
if ([self isVertical])
|
||||
{
|
||||
oldSize.width += [self dividerThickness] * (count - 1);
|
||||
@@ -256,10 +266,10 @@ var CPSplitViewHorizontalImage = nil,
|
||||
oldSize.width = CGRectGetWidth([self frame]);
|
||||
oldSize.height += [self dividerThickness] * (count - 1);
|
||||
}
|
||||
|
||||
|
||||
while (count--)
|
||||
oldSize[_sizeComponent] += [subviews[count] frame].size[_sizeComponent];
|
||||
|
||||
|
||||
[self resizeSubviewsWithOldSize:oldSize];
|
||||
}
|
||||
|
||||
@@ -268,31 +278,41 @@ var CPSplitViewHorizontalImage = nil,
|
||||
var frame = [_subviews[anIndex] frame],
|
||||
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent],
|
||||
effectiveRect = [self effectiveRectOfDividerAtIndex:anIndex],
|
||||
buttonBar = _buttonBars[anIndex],
|
||||
buttonBarRect = null,
|
||||
additionalRect = null;
|
||||
|
||||
|
||||
if (buttonBar != null)
|
||||
{
|
||||
buttonBarRect = [buttonBar resizeControlFrame];
|
||||
buttonBarRect.origin = [self convertPoint:buttonBarRect.origin fromView:buttonBar];
|
||||
}
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:effectiveRect:forDrawnRect:ofDividerAtIndex:)])
|
||||
effectiveRect = [_delegate splitView:self effectiveRect:effectiveRect forDrawnRect:effectiveRect ofDividerAtIndex:anIndex];
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)])
|
||||
additionalRect = [_delegate splitView:self additionalEffectiveRectOfDividerAtIndex:anIndex];
|
||||
|
||||
return CGRectContainsPoint(effectiveRect, aPoint) || (additionalRect && CGRectContainsPoint(additionalRect, aPoint));
|
||||
return CGRectContainsPoint(effectiveRect, aPoint) ||
|
||||
(additionalRect && CGRectContainsPoint(additionalRect, aPoint)) ||
|
||||
(buttonBarRect && CGRectContainsPoint(buttonBarRect, aPoint));
|
||||
}
|
||||
|
||||
- (CPView)hitTest:(CGPoint)aPoint
|
||||
{
|
||||
if ([self isHidden] || ![self hitTests] || !CGRectContainsPoint([self frame], aPoint))
|
||||
return nil;
|
||||
|
||||
|
||||
var point = [self convertPoint:aPoint fromView:[self superview]];
|
||||
|
||||
|
||||
var count = [_subviews count] - 1;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
if ([self cursorAtPoint:point hitDividerAtIndex:i])
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
return [super hitTest:aPoint];
|
||||
}
|
||||
|
||||
@@ -309,12 +329,13 @@ var CPSplitViewHorizontalImage = nil,
|
||||
if (_currentDivider != CPNotFound)
|
||||
{
|
||||
_currentDivider = CPNotFound;
|
||||
[self _updateResizeCursor:anEvent];
|
||||
[self _postNotificationDidResize];
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (type == CPLeftMouseDown)
|
||||
{
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
@@ -331,7 +352,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
if ([anEvent clickCount] == 2 &&
|
||||
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
|
||||
[_delegate respondsToSelector:@selector(splitView:shouldCollapseSubview:forDoubleClickOnDividerAtIndex:)])
|
||||
{
|
||||
{
|
||||
var minPosition = [self minPossiblePositionOfDividerAtIndex:i],
|
||||
maxPosition = [self maxPossiblePositionOfDividerAtIndex:i];
|
||||
|
||||
@@ -363,14 +384,16 @@ var CPSplitViewHorizontalImage = nil,
|
||||
if (_currentDivider === CPNotFound)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
else if (type == CPLeftMouseDragged && _currentDivider != CPNotFound)
|
||||
{
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
|
||||
[self setPosition:(point[_originComponent] + _initialOffset) ofDividerAtIndex:_currentDivider];
|
||||
// Cursor might change if we reach a resize limit.
|
||||
[self _updateResizeCursor:anEvent];
|
||||
}
|
||||
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackDivider:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
|
||||
@@ -380,13 +403,81 @@ var CPSplitViewHorizontalImage = nil,
|
||||
[self trackDivider:anEvent];
|
||||
}
|
||||
|
||||
- (void)viewDidMoveToWindow
|
||||
{
|
||||
// Enable split view resize cursors. Commented out pending CPTrackingArea implementation.
|
||||
//[[self window] setAcceptsMouseMovedEvents:YES];
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)anEvent
|
||||
{
|
||||
// Tracking code handles cursor by itself.
|
||||
if (_currentDivider == CPNotFound)
|
||||
[self _updateResizeCursor:anEvent];
|
||||
}
|
||||
|
||||
- (void)mouseMoved:(CPEvent)anEvent
|
||||
{
|
||||
if (_currentDivider == CPNotFound)
|
||||
[self _updateResizeCursor:anEvent];
|
||||
}
|
||||
|
||||
- (void)mouseExited:(CPEvent)anEvent
|
||||
{
|
||||
if (_currentDivider == CPNotFound)
|
||||
// FIXME: we should use CPCursor push/pop (if previous currentCursor != arrow).
|
||||
[[CPCursor arrowCursor] set];
|
||||
}
|
||||
|
||||
- (void)_updateResizeCursor:(CPEvent)anEvent
|
||||
{
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
if ([anEvent type] === CPLeftMouseUp && ![[self window] acceptsMouseMovedEvents])
|
||||
{
|
||||
[[CPCursor arrowCursor] set];
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0, count = [_subviews count] - 1; i < count; i++)
|
||||
{
|
||||
// If we are currently tracking, keep the resize cursor active even outside of hit areas.
|
||||
if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i]))
|
||||
{
|
||||
var frame = [_subviews[i] frame],
|
||||
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent],
|
||||
canShrink = [self _realPositionForPosition:startPosition-1 ofDividerAtIndex:i] < startPosition,
|
||||
canGrow = [self _realPositionForPosition:startPosition+1 ofDividerAtIndex:i] > startPosition,
|
||||
cursor = [CPCursor arrowCursor];
|
||||
|
||||
if (_isVertical && canShrink && canGrow)
|
||||
cursor = [CPCursor resizeLeftRightCursor];
|
||||
else if (_isVertical && canShrink)
|
||||
cursor = [CPCursor resizeLeftCursor];
|
||||
else if (_isVertical && canGrow)
|
||||
cursor = [CPCursor resizeRightCursor];
|
||||
else if (canShrink && canGrow)
|
||||
cursor = [CPCursor resizeUpDownCursor];
|
||||
else if (canShrink)
|
||||
cursor = [CPCursor resizeUpCursor];
|
||||
else if (canGrow)
|
||||
cursor = [CPCursor resizeDownCursor];
|
||||
|
||||
[cursor set];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[[CPCursor arrowCursor] set];
|
||||
}
|
||||
|
||||
- (float)maxPossiblePositionOfDividerAtIndex:(int)dividerIndex
|
||||
{
|
||||
var frame = [_subviews[dividerIndex + 1] frame];
|
||||
|
||||
|
||||
if (dividerIndex + 1 < [_subviews count] - 1)
|
||||
return frame.origin[_originComponent] + frame.size[_sizeComponent] - [self dividerThickness];
|
||||
else
|
||||
else
|
||||
return [self frame].size[_sizeComponent] - [self dividerThickness];
|
||||
}
|
||||
|
||||
@@ -395,17 +486,15 @@ var CPSplitViewHorizontalImage = nil,
|
||||
if (dividerIndex > 0)
|
||||
{
|
||||
var frame = [_subviews[dividerIndex - 1] frame];
|
||||
|
||||
|
||||
return frame.origin[_originComponent] + frame.size[_sizeComponent] + [self dividerThickness];
|
||||
}
|
||||
else
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (void)setPosition:(float)position ofDividerAtIndex:(int)dividerIndex
|
||||
- (int)_realPositionForPosition:(float)position ofDividerAtIndex:(int)dividerIndex
|
||||
{
|
||||
[self _adjustSubviewsWithCalculatedSize];
|
||||
|
||||
// not sure where this should override other positions?
|
||||
if ([_delegate respondsToSelector:@selector(splitView:constrainSplitPosition:ofSubviewAt:)])
|
||||
position = [_delegate splitView:self constrainSplitPosition:position ofSubviewAt:dividerIndex];
|
||||
@@ -414,47 +503,56 @@ var CPSplitViewHorizontalImage = nil,
|
||||
proposedMin = [self minPossiblePositionOfDividerAtIndex:dividerIndex],
|
||||
actualMax = proposedMax,
|
||||
actualMin = proposedMin;
|
||||
|
||||
|
||||
if([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)])
|
||||
actualMin = [_delegate splitView:self constrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex];
|
||||
|
||||
|
||||
if([_delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)])
|
||||
actualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
|
||||
|
||||
var frame = [self frame],
|
||||
viewA = _subviews[dividerIndex],
|
||||
frameA = [viewA frame],
|
||||
viewB = _subviews[dividerIndex + 1],
|
||||
frameB = [viewB frame];
|
||||
var viewA = _subviews[dividerIndex],
|
||||
realPosition = MAX(MIN(position, actualMax), actualMin);
|
||||
|
||||
var realPosition = MAX(MIN(position, actualMax), actualMin);
|
||||
|
||||
if (position < proposedMin + (actualMin - proposedMin) / 2)
|
||||
if ([_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)])
|
||||
if ([_delegate splitView:self canCollapseSubview:viewA])
|
||||
realPosition = proposedMin;
|
||||
|
||||
|
||||
return realPosition;
|
||||
}
|
||||
|
||||
- (void)setPosition:(float)position ofDividerAtIndex:(int)dividerIndex
|
||||
{
|
||||
[self _adjustSubviewsWithCalculatedSize];
|
||||
|
||||
var realPosition = [self _realPositionForPosition:position ofDividerAtIndex:dividerIndex];
|
||||
|
||||
var viewA = _subviews[dividerIndex],
|
||||
frameA = [viewA frame],
|
||||
viewB = _subviews[dividerIndex + 1],
|
||||
frameB = [viewB frame];
|
||||
|
||||
frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent];
|
||||
[_subviews[dividerIndex] setFrame:frameA];
|
||||
|
||||
|
||||
frameB.size[_sizeComponent] = frameB.origin[_originComponent] + frameB.size[_sizeComponent] - realPosition - [self dividerThickness];
|
||||
frameB.origin[_originComponent] = realPosition + [self dividerThickness];
|
||||
[_subviews[dividerIndex + 1] setFrame:frameB];
|
||||
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)setFrameSize:(CGSize)aSize
|
||||
{
|
||||
[self _adjustSubviewsWithCalculatedSize];
|
||||
|
||||
|
||||
[super setFrameSize:aSize];
|
||||
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)resizeSubviewsWithOldSize:(CPSize)oldSize
|
||||
{
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(splitView:resizeSubviewsWithOldSize:)])
|
||||
{
|
||||
[_delegate splitView:self resizeSubviewsWithOldSize:oldSize];
|
||||
@@ -462,7 +560,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
}
|
||||
|
||||
[self _postNotificationWillResize];
|
||||
|
||||
|
||||
var index = 0,
|
||||
count = [_subviews count],
|
||||
bounds = [self bounds],
|
||||
@@ -512,10 +610,8 @@ var CPSplitViewHorizontalImage = nil,
|
||||
}
|
||||
else if (totalSizableSpace && !isSizable)
|
||||
viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent];
|
||||
else
|
||||
alert("SHOULD NEVER GET HERE");
|
||||
|
||||
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
|
||||
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
|
||||
|
||||
[view setFrame:viewFrame];
|
||||
}
|
||||
@@ -529,7 +625,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
[[CPNotificationCenter defaultCenter] removeObserver:_delegate name:CPSplitViewDidResizeSubviewsNotification object:self];
|
||||
if ([_delegate respondsToSelector:@selector(splitViewWillResizeSubviews:)])
|
||||
[[CPNotificationCenter defaultCenter] removeObserver:_delegate name:CPSplitViewWillResizeSubviewsNotification object:self];
|
||||
|
||||
|
||||
_delegate = delegate;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitViewDidResizeSubviews:)])
|
||||
@@ -544,6 +640,47 @@ var CPSplitViewHorizontalImage = nil,
|
||||
object:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the button bar who's resize control should act as a control for this splitview.
|
||||
Each divider can have at most one button bar assigned to it, and that button bar must be
|
||||
a subview of one of the split view's subviews.
|
||||
|
||||
Calling this method with nil as the button bar will remove any currently assigned button bar
|
||||
for the divider at that index. Indexes will not be adjusted as new subviews are added, so you
|
||||
should usually call this method after adding all the desired subviews to the split view.
|
||||
|
||||
This method will automatically configure the hasResizeControl and resizeControlIsLeftAligned
|
||||
parameters of the button bar, and will override any currently set values.
|
||||
*/
|
||||
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex
|
||||
{
|
||||
if (!aButtonBar)
|
||||
{
|
||||
_buttonBars[dividerIndex] = nil;
|
||||
return;
|
||||
}
|
||||
|
||||
var view = [aButtonBar superview],
|
||||
subview = aButtonBar;
|
||||
|
||||
while (view && view !== self)
|
||||
{
|
||||
subview = view;
|
||||
view = [view superview];
|
||||
}
|
||||
|
||||
if (view !== self)
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
reason:@"CPSplitView button bar must be a subview of the split view."];
|
||||
|
||||
var viewIndex = [[self subviews] indexOfObject:subview];
|
||||
|
||||
[aButtonBar setHasResizeControl:YES];
|
||||
[aButtonBar setResizeControlIsLeftAligned:dividerIndex < viewIndex];
|
||||
|
||||
_buttonBars[dividerIndex] = aButtonBar;
|
||||
}
|
||||
|
||||
- (void)_postNotificationWillResize
|
||||
{
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewWillResizeSubviewsNotification object:self];
|
||||
@@ -558,7 +695,8 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||
CPSplitViewIsVerticalKey = "CPSplitViewIsVerticalKey",
|
||||
CPSplitViewIsPaneSplitterKey = "CPSplitViewIsPaneSplitterKey";
|
||||
CPSplitViewIsPaneSplitterKey = "CPSplitViewIsPaneSplitterKey",
|
||||
CPSplitViewButtonBarsKey = "CPSplitViewButtonBarsKey";
|
||||
|
||||
@implementation CPSplitView (CPCoding)
|
||||
|
||||
@@ -569,19 +707,21 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_currentDivider = CPNotFound;
|
||||
|
||||
|
||||
_DOMDividerElements = [];
|
||||
|
||||
_buttonBars = [aCoder decodeObjectForKey:CPSplitViewButtonBarsKey] || [];
|
||||
|
||||
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];;
|
||||
|
||||
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];
|
||||
|
||||
_isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey];
|
||||
[self _setVertical:[aCoder decodeBoolForKey:CPSplitViewIsVerticalKey]];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -592,9 +732,12 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
|
||||
//FIXME how should we handle this?
|
||||
//[aCoder encodeObject:_buttonBars forKey:CPSplitViewButtonBarsKey];
|
||||
|
||||
[aCoder encodeConditionalObject:_delegate forKey:CPSplitViewDelegateKey];
|
||||
|
||||
|
||||
[aCoder encodeBool:_isVertical forKey:CPSplitViewIsVerticalKey];
|
||||
[aCoder encodeBool:_isPaneSplitter forKey:CPSplitViewIsPaneSplitterKey];
|
||||
}
|
||||
|
||||
+18
-5
@@ -247,6 +247,8 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
[_labelsView tabView:self didAddTabViewItem:aTabViewItem];
|
||||
|
||||
[aTabViewItem _setTabView:self];
|
||||
|
||||
if ([_tabViewItems count] == 1)
|
||||
[self selectFirstTabViewItem:self];
|
||||
|
||||
@@ -260,9 +262,13 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)removeTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
[_tabViewItems removeObjectIdenticalTo:aTabViewItem];
|
||||
var index = [self indexOfTabViewItem:aTabViewItem];
|
||||
|
||||
[_labelsView tabView:self didRemoveTabViewItem:aTabViewItem];
|
||||
[_tabViewItems removeObjectIdenticalTo:aTabViewItem];
|
||||
|
||||
[_labelsView tabView:self didRemoveTabViewItemAtIndex:index];
|
||||
|
||||
[aTabViewItem _setTabView:nil];
|
||||
|
||||
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
||||
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
|
||||
@@ -490,6 +496,14 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
return contentRect;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the receiver's delegate.
|
||||
*/
|
||||
- (id)delegate
|
||||
{
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the delegate for this tab view.
|
||||
@param aDelegate the tab view's delegate
|
||||
@@ -648,10 +662,9 @@ var _CPTabLabelsViewBackgroundColor = nil,
|
||||
[self layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)tabView:(CPTabView)aTabView didRemoveTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
- (void)tabView:(CPTabView)aTabView didRemoveTabViewItemAtIndex:(unsigned)index
|
||||
{
|
||||
var index = [aTabView indexOfTabViewItem:aTabViewItem],
|
||||
label = _tabLabels[index];
|
||||
var label = _tabLabels[index];
|
||||
|
||||
[_tabLabels removeObjectAtIndex:index];
|
||||
|
||||
|
||||
@@ -58,6 +58,13 @@ CPPressedTab = 2;
|
||||
|
||||
CPView _view;
|
||||
CPView _auxiliaryView;
|
||||
|
||||
CPTabView _tabView;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initWithIdentifier:@""];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -163,6 +170,14 @@ CPPressedTab = 2;
|
||||
return _tabView;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)_setTabView:(CPTabView)aView
|
||||
{
|
||||
_tabView = aView;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
|
||||
|
||||
+85
-44
@@ -27,22 +27,11 @@
|
||||
|
||||
@import "CPTableHeaderView.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
/*
|
||||
@global
|
||||
@class CPTableColumn
|
||||
*/
|
||||
CPTableColumnNoResizing = 0;
|
||||
/*
|
||||
@global
|
||||
@class CPTableColumn
|
||||
*/
|
||||
CPTableColumnAutoresizingMask = 1;
|
||||
/*
|
||||
@global
|
||||
@class CPTableColumn
|
||||
*/
|
||||
CPTableColumnUserResizingMask = 2;
|
||||
CPTableColumnAutoresizingMask = 1 << 0;
|
||||
CPTableColumnUserResizingMask = 1 << 1;
|
||||
|
||||
@implementation CPTableColumn : CPObject
|
||||
{
|
||||
@@ -54,12 +43,20 @@ CPTableColumnUserResizingMask = 2;
|
||||
float _width;
|
||||
float _minWidth;
|
||||
float _maxWidth;
|
||||
unsigned _resizingMask;
|
||||
|
||||
id _identifier;
|
||||
BOOL _isEditable;
|
||||
CPSortDescriptor _sortDescriptorPrototype;
|
||||
BOOL _isHidden;
|
||||
CPString _headerToolTip;
|
||||
|
||||
BOOL _disableResizingPosting @accessors(property=disableResizingPosting);
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initWithIdentifier:@""];
|
||||
}
|
||||
|
||||
- (id)initWithIdentifier:(id)anIdentifier
|
||||
@@ -73,15 +70,27 @@ CPTableColumnUserResizingMask = 2;
|
||||
_width = 100.0;
|
||||
_minWidth = 10.0;
|
||||
_maxWidth = 1000000.0;
|
||||
|
||||
_resizingMask = CPTableColumnAutoresizingMask | CPTableColumnUserResizingMask;
|
||||
_disableResizingPosting = NO;
|
||||
|
||||
[self setIdentifier:anIdentifier];
|
||||
[self setHeaderView:[CPTextField new]];
|
||||
[self setDataView:[CPTextField new]];
|
||||
|
||||
var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()];
|
||||
[self setHeaderView:header];
|
||||
|
||||
var textDataView = [CPTextField new];
|
||||
[textDataView setLineBreakMode:CPLineBreakByTruncatingTail];
|
||||
[textDataView setValue:[CPColor colorWithHexString:@"333333"] forThemeAttribute:@"text-color"];
|
||||
[textDataView setValue:[CPColor whiteColor] forThemeAttribute:@"text-color" inState:CPThemeStateSelected];
|
||||
[textDataView setValue:[CPFont boldSystemFontOfSize:12] forThemeAttribute:@"font" inState:CPThemeStateSelected];
|
||||
[textDataView setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
|
||||
[self setDataView:textDataView];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)setTableView:(CPTableView)aTableView
|
||||
{
|
||||
_tableView = aTableView;
|
||||
@@ -112,18 +121,23 @@ CPTableColumnUserResizingMask = 2;
|
||||
|
||||
if (tableView)
|
||||
{
|
||||
var index = [[tableView tableColumns] indexOfObjectIdenticalTo:self];
|
||||
|
||||
// FIXME: THIS IS HORRIBLE. Don't just reload everything when a table column changes, just relayout the changed widths.
|
||||
tableView._reloadAllRows = YES;
|
||||
tableView._dirtyTableColumnRangeIndex = tableView._dirtyTableColumnRangeIndex < 0 ? index : MIN(index, tableView._dirtyTableColumnRangeIndex);
|
||||
|
||||
var index = [[tableView tableColumns] indexOfObjectIdenticalTo:self],
|
||||
dirtyTableColumnRangeIndex = tableView._dirtyTableColumnRangeIndex;
|
||||
|
||||
if (dirtyTableColumnRangeIndex < 0)
|
||||
tableView._dirtyTableColumnRangeIndex = index;
|
||||
else
|
||||
tableView._dirtyTableColumnRangeIndex = MIN(index, tableView._dirtyTableColumnRangeIndex);
|
||||
|
||||
var rows = tableView._exposedRows,
|
||||
columns = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(index, [tableView._exposedColumns lastIndex] - index + 1)];
|
||||
|
||||
// FIXME: Would be faster with some sort of -setNeedsDisplayInColumns: that updates a dirtyTableColumnForDisplay cache; then marked columns would relayout their data views at display time.
|
||||
[tableView _layoutDataViewsInRows:rows columns:columns];
|
||||
[tableView tile];
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPTableViewColumnDidResizeNotification
|
||||
object:tableView
|
||||
userInfo:[CPDictionary dictionaryWithObjects:[self, oldWidth] forKeys:[@"CPTableColumn", "CPOldWidth"]]];
|
||||
|
||||
if (!_disableResizingPosting)
|
||||
[self _postDidResizeNotificationWithOldWidth:oldWidth];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +177,7 @@ CPTableColumnUserResizingMask = 2;
|
||||
_maxWidth = aMaxWidth;
|
||||
|
||||
var width = [self width],
|
||||
newWidth = MAX(width, [self maxWidth]);
|
||||
newWidth = MIN(width, [self maxWidth]);
|
||||
|
||||
if (width !== newWidth)
|
||||
[self setWidth:newWidth];
|
||||
@@ -179,7 +193,7 @@ CPTableColumnUserResizingMask = 2;
|
||||
_resizingMask = aResizingMask;
|
||||
}
|
||||
|
||||
- (float)resizingMask
|
||||
- (unsigned)resizingMask
|
||||
{
|
||||
return _resizingMask;
|
||||
}
|
||||
@@ -204,6 +218,11 @@ CPTableColumnUserResizingMask = 2;
|
||||
[CPException raise:CPInvalidArgumentException reason:@"Attempt to set nil header view on " + [self description]];
|
||||
|
||||
_headerView = aView;
|
||||
|
||||
var tableHeaderView = [_tableView headerView];
|
||||
|
||||
[tableHeaderView setNeedsLayout];
|
||||
[tableHeaderView setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (CPView)headerView
|
||||
@@ -211,6 +230,22 @@ CPTableColumnUserResizingMask = 2;
|
||||
return _headerView;
|
||||
}
|
||||
|
||||
/*!
|
||||
This method set's the "prototype" view which will be used to create all table cells in this column.
|
||||
|
||||
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
|
||||
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
|
||||
|
||||
Example:
|
||||
|
||||
[tableColumn setDataView:someView]; // snapshot taken
|
||||
[[tableColumn dataView] setSomething:x]; //won't work
|
||||
|
||||
This doesn't work because the snapshot is taken before the new property is applied. Instead, do:
|
||||
|
||||
[someView setSomething:x];
|
||||
[tableColumn setDataView:someView];
|
||||
*/
|
||||
- (void)setDataView:(CPView)aView
|
||||
{
|
||||
if (_dataView === aView)
|
||||
@@ -246,9 +281,9 @@ CPTableColumnUserResizingMask = 2;
|
||||
var dataView = [self dataViewForRow:aRowIndex],
|
||||
dataViewUID = [dataView UID];
|
||||
|
||||
var x = [self tableView]._cachedDataViews[dataViewUID];
|
||||
if (x && x.length)
|
||||
return x.pop();
|
||||
var x = [self tableView]._cachedDataViews[dataViewUID];
|
||||
if (x && x.length)
|
||||
return x.pop();
|
||||
|
||||
// if we haven't cached an archive of the data view, do it now
|
||||
if (!_dataViewData[dataViewUID])
|
||||
@@ -256,7 +291,8 @@ return x.pop();
|
||||
|
||||
// unarchive the data view cache
|
||||
var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]];
|
||||
newDataView.identifier = dataViewUID;
|
||||
newDataView.identifier = dataViewUID;
|
||||
|
||||
return newDataView;
|
||||
}
|
||||
|
||||
@@ -336,6 +372,14 @@ newDataView.identifier = dataViewUID;
|
||||
return _headerToolTip;
|
||||
}
|
||||
|
||||
- (void)_postDidResizeNotificationWithOldWidth:(float)oldWidth
|
||||
{
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPTableViewColumnDidResizeNotification
|
||||
object:[self tableView]
|
||||
userInfo:[CPDictionary dictionaryWithObjects:[self, oldWidth] forKeys:[@"CPTableColumn", "CPOldWidth"]]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPTableColumn (Bindings)
|
||||
@@ -400,14 +444,11 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
_maxWidth = [aCoder decodeFloatForKey:CPTableColumnMaxWidthKey];
|
||||
|
||||
[self setIdentifier:[aCoder decodeObjectForKey:CPTableColumnIdentifierKey]];
|
||||
// [self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
||||
// [self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
|
||||
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
||||
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
|
||||
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
||||
|
||||
[self setHeaderView:[CPTextField new]];
|
||||
[self setDataView:[CPTextField new]];
|
||||
|
||||
|
||||
// _resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
|
||||
_resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -421,10 +462,10 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
[aCoder encodeObject:_minWidth forKey:CPTableColumnMinWidthKey];
|
||||
[aCoder encodeObject:_maxWidth forKey:CPTableColumnMaxWidthKey];
|
||||
|
||||
// [aCoder encodeObject:_headerView forKey:CPTableColumnHeaderViewKey];
|
||||
// [aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
|
||||
[aCoder encodeObject:_headerView forKey:CPTableColumnHeaderViewKey];
|
||||
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
|
||||
|
||||
// [aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
|
||||
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+420
-66
@@ -23,123 +23,477 @@
|
||||
@import "CPTableColumn.j"
|
||||
@import "CPTableView.j"
|
||||
@import "CPView.j"
|
||||
|
||||
@implementation _CPTableColumnHeaderView : CPView
|
||||
{
|
||||
_CPImageAndTextView _textField;
|
||||
}
|
||||
|
||||
- (void)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self)
|
||||
{
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_textField = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(5, 1, CGRectGetWidth([self bounds]) - 10, CGRectGetHeight([self bounds]) - 1)];
|
||||
[_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
|
||||
[_textField setLineBreakMode:CPLineBreakByTruncatingTail];
|
||||
[_textField setTextColor: [CPColor colorWithHexString: @"333333"]];
|
||||
[_textField setFont:[CPFont boldSystemFontOfSize:12.0]];
|
||||
[_textField setAlignment:CPLeftTextAlignment];
|
||||
[_textField setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||
[_textField setTextShadowColor:[CPColor whiteColor]];
|
||||
[_textField setTextShadowOffset:CGSizeMake(0,1)];
|
||||
|
||||
[self addSubview:_textField];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var themeState = [self themeState];
|
||||
|
||||
if(themeState & CPThemeStateSelected && themeState & CPThemeStateHighlighted)
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted-pressed.png", CGSizeMake(1.0, 22.0))]];
|
||||
else if (themeState & CPThemeStateSelected)
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted.png", CGSizeMake(1.0, 22.0))]];
|
||||
else if (themeState & CPThemeStateHighlighted)
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-pressed.png", CGSizeMake(1.0, 22.0))]];
|
||||
else
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(CPString)string
|
||||
{
|
||||
[_textField setText:string];
|
||||
}
|
||||
|
||||
- (CPString)stringValue
|
||||
{
|
||||
return [_textField text];
|
||||
}
|
||||
|
||||
- (void)textField
|
||||
{
|
||||
return _textField;
|
||||
}
|
||||
|
||||
- (void)sizeToFit
|
||||
{
|
||||
[_textField sizeToFit];
|
||||
}
|
||||
|
||||
- (void)setFont:(CPFont)aFont
|
||||
{
|
||||
[_textField setFont:aFont];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forThemeAttribute:(id)aKey
|
||||
{
|
||||
[_textField setValue:aValue forThemeAttribute:aKey];
|
||||
}
|
||||
|
||||
- (void)_setIndicatorImage:(CPImage)anImage
|
||||
{
|
||||
if (anImage)
|
||||
{
|
||||
[_textField setImage:anImage];
|
||||
[_textField setImagePosition:CPImageRight];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_textField setImagePosition:CPNoImage];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringValueKey",
|
||||
_CPTableColumnHeaderViewFontKey = @"_CPTableColumnHeaderViewFontKey",
|
||||
_CPTableColumnHeaderViewImageKey = @"_CPTableColumnHeaderViewImageKey";
|
||||
|
||||
@implementation _CPTableColumnHeaderView (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
[self _init];
|
||||
[self _setIndicatorImage:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewImageKey]];
|
||||
[self setStringValue:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewStringValueKey]];
|
||||
[self setFont:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewFontKey]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:[_textField text] forKey:_CPTableColumnHeaderViewStringValueKey];
|
||||
[aCoder encodeObject:[_textField image] forKey:_CPTableColumnHeaderViewImageKey];
|
||||
[aCoder encodeObject:[_textField font] forKey:_CPTableColumnHeaderViewFontKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPTableHeaderView : CPView
|
||||
{
|
||||
int _resizedColumn @accessors(readonly, property=resizedColumn);
|
||||
int _draggedColumn @accessors(readonly, property=draggedColumn);
|
||||
int _pressedColumn @accessors(readonly, property=pressedColumn);
|
||||
|
||||
float _draggedDistance @accessors(readonly, property=draggedDistance);
|
||||
float _lastLocation;
|
||||
float _columnOldWidth;
|
||||
|
||||
CPTableView _tableView @accessors(property=tableView);
|
||||
}
|
||||
|
||||
- (void)initWithFrame:(CGRect)aFrame
|
||||
- (void)_init
|
||||
{
|
||||
_resizedColumn = -1;
|
||||
_draggedColumn = -1;
|
||||
_pressedColumn = -1;
|
||||
_draggedDistance = 0.0;
|
||||
_lastLocation = nil;
|
||||
_columnOldWidth = nil;
|
||||
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_resizedColumn = CPNotFound;
|
||||
_draggedColumn = CPNotFound;
|
||||
_draggedDistance = 0.0;
|
||||
}
|
||||
[self _init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (int)columnAtPoint:(CGPoint)aPoint
|
||||
{
|
||||
if (!CGRectContainsPoint([self bounds], aPoint))
|
||||
return CPNotFound;
|
||||
|
||||
// at this point, we can essentially ignore height, because all columns have equal heights
|
||||
// and that height is equal to the height of our own bounds, which we know we are inside of
|
||||
|
||||
var index = 0,
|
||||
count = [[_tableView tableColumns] count],
|
||||
tableSpacing = [_tableView intercellSpacing],
|
||||
tableColumns = [_tableView tableColumns],
|
||||
leftOffset = 0,
|
||||
pointX = aPoint.x;
|
||||
|
||||
for (; index < count; index++)
|
||||
{
|
||||
var width = [tableColumns[index] width] + tableSpacing.width;
|
||||
|
||||
if (pointX >= leftOffset && pointX < leftOffset + width)
|
||||
return index;
|
||||
|
||||
leftOffset += width;
|
||||
}
|
||||
|
||||
return CPNotFound;
|
||||
return [_tableView columnAtPoint:CGPointMake(aPoint.x, 0)];
|
||||
}
|
||||
|
||||
- (CGRect)headerRectOfColumn:(int)aColumnIndex
|
||||
{
|
||||
var tableColumns = [_tableView tableColumns],
|
||||
tableSpacing = [_tableView intercellSpacing],
|
||||
bounds = [self bounds];
|
||||
var tableColumns = [_tableView tableColumns];
|
||||
|
||||
if (aColumnIndex < 0 || aColumnIndex > [tableColumns count])
|
||||
[CPException raise:"invalid" reason:"tried to get headerRectOfColumn: on invalid column"];
|
||||
|
||||
bounds.size.width = [tableColumns[aColumnIndex] width] + tableSpacing.width;
|
||||
|
||||
while (--aColumnIndex >= 0)
|
||||
bounds.origin.x += [tableColumns[aColumnIndex] width] + tableSpacing.width;
|
||||
// UPDATE COLUMN RANGES ?
|
||||
|
||||
var tableRange = _tableView._tableColumnRanges[aColumnIndex],
|
||||
bounds = [self bounds];
|
||||
|
||||
var rMinX = ROUND(tableRange.location);
|
||||
bounds.origin.x = rMinX;
|
||||
bounds.size.width = FLOOR(tableRange.length + tableRange.location - rMinX);
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
- (CGRect)_cursorRectForColumn:(int)column
|
||||
{
|
||||
if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask))
|
||||
return CGRectMakeZero();
|
||||
|
||||
var rect = [self headerRectOfColumn:column];
|
||||
|
||||
rect.origin.x = CGRectGetMaxX(rect) - 5;
|
||||
rect.size.width = 20;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
- (void)_setPressedColumn:(CPInteger)column
|
||||
{
|
||||
if (_pressedColumn != -1)
|
||||
{
|
||||
var headerView = [_tableView._tableColumns[_pressedColumn] headerView];
|
||||
[headerView unsetThemeState:CPThemeStateHighlighted];
|
||||
}
|
||||
|
||||
if (column != -1)
|
||||
{
|
||||
var headerView = [_tableView._tableColumns[column] headerView];
|
||||
[headerView setThemeState:CPThemeStateHighlighted];
|
||||
}
|
||||
|
||||
_pressedColumn = column;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)theEvent
|
||||
{
|
||||
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
|
||||
clickedColumn = [self columnAtPoint:mouseLocation];
|
||||
|
||||
// should we send column -1 ?
|
||||
[_tableView _sendDelegateDidMouseDownInHeader:clickedColumn];
|
||||
|
||||
var resizeLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
|
||||
resizedColumn = [self columnAtPoint:resizeLocation];
|
||||
|
||||
if (resizedColumn == -1)
|
||||
return;
|
||||
|
||||
// 2 different tracking methods: one for resizing/stop-resizing, another one for selection/reordering
|
||||
if ([_tableView allowsColumnResizing]
|
||||
&& CGRectContainsPoint([self _cursorRectForColumn:resizedColumn], mouseLocation))
|
||||
{
|
||||
_resizedColumn = resizedColumn;
|
||||
[_tableView._tableColumns[_resizedColumn] setDisableResizingPosting:YES];
|
||||
[_tableView setDisableAutomaticResizing:YES];
|
||||
[self trackResizeWithEvent:theEvent];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self _setPressedColumn:clickedColumn];
|
||||
[self trackMouseWithEvent:theEvent];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)trackMouseWithEvent:(CPEvent)theEvent
|
||||
{
|
||||
var type = [theEvent type];
|
||||
|
||||
if (type == CPLeftMouseUp)
|
||||
{
|
||||
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
|
||||
clickedColumn = [self columnAtPoint:location];
|
||||
|
||||
[self _setPressedColumn:-1];
|
||||
|
||||
if (clickedColumn != -1)
|
||||
[_tableView _didClickTableColumn:clickedColumn modifierFlags:[theEvent modifierFlags]];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackMouseWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPLeftMouseDownMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
|
||||
- (void)trackResizeWithEvent:(CPEvent)anEvent
|
||||
{
|
||||
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
tableColumn = [[_tableView tableColumns] objectAtIndex:_resizedColumn],
|
||||
type = [anEvent type];
|
||||
|
||||
if (_lastLocation == nil)
|
||||
_lastLocation = location;
|
||||
|
||||
if (_columnOldWidth == nil)
|
||||
_columnOldWidth = [tableColumn width];
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
{
|
||||
[self _updateResizeCursor:anEvent];
|
||||
|
||||
[tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth];
|
||||
[tableColumn setDisableResizingPosting:NO];
|
||||
[_tableView setDisableAutomaticResizing:NO];
|
||||
|
||||
_resizedColumn = -1;
|
||||
_lastLocation = nil;
|
||||
_columnOldWidth = nil;
|
||||
|
||||
return;
|
||||
}
|
||||
else if (type === CPLeftMouseDragged)
|
||||
{
|
||||
var newWidth = [tableColumn width] + location.x - _lastLocation.x;
|
||||
|
||||
if (newWidth < [tableColumn minWidth])
|
||||
[[CPCursor resizeRightCursor] set];
|
||||
else if (newWidth > [tableColumn maxWidth])
|
||||
[[CPCursor resizeLeftCursor] set];
|
||||
else
|
||||
{
|
||||
_tableView._lastColumnShouldSnap = NO;
|
||||
[tableColumn setWidth:newWidth];
|
||||
// FIXME: there has to be a better way to do this...
|
||||
// We should refactor the auto resizing crap.
|
||||
// We need to figure out the exact cocoa behavior here though.
|
||||
_lastLocation = location;
|
||||
|
||||
[[CPCursor resizeLeftRightCursor] set];
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
}
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
|
||||
- (void)_updateResizeCursor:(CPEvent)theEvent
|
||||
{
|
||||
// never get stuck in resize cursor mode (FIXME take out when we turn on tracking rects)
|
||||
if (![_tableView allowsColumnResizing] || ([theEvent type] === CPLeftMouseUp && ![[self window] acceptsMouseMovedEvents]))
|
||||
{
|
||||
[[CPCursor arrowCursor] set];
|
||||
return;
|
||||
}
|
||||
|
||||
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
|
||||
mouseOverLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
|
||||
overColumn = [self columnAtPoint:mouseOverLocation];
|
||||
|
||||
if (overColumn >= 0 && CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation))
|
||||
{
|
||||
var tableColumn = [[_tableView tableColumns] objectAtIndex:overColumn],
|
||||
width = [tableColumn width];
|
||||
|
||||
if (width == [tableColumn minWidth])
|
||||
[[CPCursor resizeRightCursor] set];
|
||||
else if (width == [tableColumn maxWidth])
|
||||
[[CPCursor resizeLeftCursor] set];
|
||||
else
|
||||
[[CPCursor resizeLeftRightCursor] set];
|
||||
}
|
||||
else
|
||||
[[CPCursor arrowCursor] set];
|
||||
}
|
||||
|
||||
- (void)viewDidMoveToWindow
|
||||
{
|
||||
//if ([_tableView allowsColumnResizing])
|
||||
// [[self window] setAcceptsMouseMovedEvents:YES];
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)theEvent
|
||||
{
|
||||
[self _updateResizeCursor:theEvent];
|
||||
}
|
||||
|
||||
- (void)mouseMoved:(CPEvent)theEvent
|
||||
{
|
||||
[self _updateResizeCursor:theEvent];
|
||||
}
|
||||
|
||||
- (void)mouseExited:(CPEvent)theEvent
|
||||
{
|
||||
// FIXME: we should use CPCursor push/pop (if previous currentCursor != arrow).
|
||||
[[CPCursor arrowCursor] set];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var tableColumns = [_tableView tableColumns],
|
||||
count = [tableColumns count],
|
||||
columnRect = [self bounds],
|
||||
spacing = [_tableView intercellSpacing];
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
var tableColumns = [_tableView tableColumns],
|
||||
count = [tableColumns count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var column = [tableColumns objectAtIndex:i],
|
||||
headerView = [column headerView];
|
||||
|
||||
columnRect.size.width = [column width] + spacing.width;
|
||||
|
||||
[headerView setFrame:columnRect];
|
||||
|
||||
columnRect.origin.x += [column width] + spacing.width;
|
||||
|
||||
[self addSubview:headerView];
|
||||
|
||||
var frame = [self headerRectOfColumn:i];
|
||||
frame.size.height -= 0.5;
|
||||
if (i > 0)
|
||||
{
|
||||
frame.origin.x += 0.5;
|
||||
frame.size.width -= 1;
|
||||
}
|
||||
|
||||
[headerView setFrame:frame];
|
||||
|
||||
if([headerView superview] != self)
|
||||
[self addSubview:headerView];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
[[_tableView gridColor] setStroke];
|
||||
if (!_tableView)
|
||||
return;
|
||||
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
exposedColumnIndexes = exposedColumnIndexes = [_tableView columnIndexesInRect:aRect],
|
||||
columnsArray = [];
|
||||
exposedColumnIndexes = [_tableView columnIndexesInRect:aRect],
|
||||
columnsArray = [],
|
||||
tableColumns = [_tableView tableColumns],
|
||||
exposedTableColumns = _tableView._exposedColumns,
|
||||
firstIndex = [exposedTableColumns firstIndex],
|
||||
exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1);
|
||||
|
||||
[exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:nil];
|
||||
CGContextSetLineWidth(context, 1);
|
||||
CGContextSetStrokeColor(context, [_tableView gridColor]);
|
||||
|
||||
[exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange];
|
||||
|
||||
var columnArrayIndex = 0,
|
||||
columnArrayCount = columnsArray.length;
|
||||
|
||||
for(; columnArrayIndex < columnArrayCount; ++columnArrayIndex)
|
||||
columnArrayCount = columnsArray.length,
|
||||
columnMaxX;
|
||||
|
||||
CGContextBeginPath(context);
|
||||
for(; columnArrayIndex < columnArrayCount; columnArrayIndex++)
|
||||
{
|
||||
// grab each column rect and add horizontal lines
|
||||
var columnToStroke = [self headerRectOfColumn:columnArrayIndex];
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, ROUND(columnToStroke.origin.x + columnToStroke.size.width) - 0.5, ROUND(columnToStroke.origin.y) - 0.5);
|
||||
CGContextAddLineToPoint(context, ROUND(columnToStroke.origin.x + columnToStroke.size.width) - 0.5, ROUND(columnToStroke.origin.y + columnToStroke.size.height) - 0.5);
|
||||
CGContextSetLineWidth(context, 1);
|
||||
CGContextStrokePath(context);
|
||||
// grab each column rect and add vertical lines
|
||||
var columnIndex = columnsArray[columnArrayIndex],
|
||||
columnToStroke = [self headerRectOfColumn:columnIndex];
|
||||
|
||||
columnMaxX = CGRectGetMaxX(columnToStroke);
|
||||
|
||||
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMinY(columnToStroke)));
|
||||
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMaxY(columnToStroke)));
|
||||
}
|
||||
|
||||
CGContextClosePath(context);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
/*
|
||||
var maxY = CGRectGetMaxY([self bounds]);
|
||||
// draw normal gradient for remaining space
|
||||
if (supportsCanvasGradient)
|
||||
{
|
||||
aRect.origin.x = columnMaxX - 0.5;
|
||||
aRect.size.width -= columnMaxX;
|
||||
CGContextBeginPath(context);
|
||||
CGContextAddRect(context, CGRectMake(columnMaxX + 1, 0, CGRectGetMaxX([self bounds]) - columnMaxX, CGRectGetHeight([self bounds])));
|
||||
CGContextClosePath(context);
|
||||
CGContextDrawLinearGradient(context, [_CPTableColumnHeaderView headerGradient], CGPointMake(0,0), CGPointMake(0, maxY - 1),0);
|
||||
}
|
||||
|
||||
// Draw bottom line
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, 0, maxY - 0.5);
|
||||
CGContextAddLineToPoint(context, CGRectGetMaxX([self bounds]), maxY - 0.5);
|
||||
CGContextClosePath(context);
|
||||
CGContextStrokePath(context);
|
||||
*/
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
|
||||
|
||||
@implementation CPTableHeaderView (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
[self _init];
|
||||
_tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
[aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+1697
-148
File diff suppressed because it is too large.
Load diff
+298
-142
@@ -24,56 +24,17 @@
|
||||
@import "CPControl.j"
|
||||
@import "CPStringDrawing.j"
|
||||
@import "CPCompatibility.j"
|
||||
@import "_CPImageAndTextView.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
#include "Platform/Platform.h"
|
||||
#include "Platform/DOM/CPDOMDisplayServer.h"
|
||||
|
||||
CPTextFieldSquareBezel = 0; /*! A textfield bezel with a squared corners. */
|
||||
CPTextFieldRoundedBezel = 1; /*! A textfield bezel with rounded corners. */
|
||||
|
||||
/*
|
||||
@global
|
||||
@group CPLineBreakMode
|
||||
*/
|
||||
CPLineBreakByWordWrapping = 0;
|
||||
/*
|
||||
@global
|
||||
@group CPLineBreakMode
|
||||
*/
|
||||
CPLineBreakByCharWrapping = 1;
|
||||
/*
|
||||
@global
|
||||
@group CPLineBreakMode
|
||||
*/
|
||||
CPLineBreakByClipping = 2;
|
||||
/*
|
||||
@global
|
||||
@group CPLineBreakMode
|
||||
*/
|
||||
CPLineBreakByTruncatingHead = 3;
|
||||
/*
|
||||
@global
|
||||
@group CPLineBreakMode
|
||||
*/
|
||||
CPLineBreakByTruncatingTail = 4;
|
||||
/*
|
||||
@global
|
||||
@group CPLineBreakMode
|
||||
*/
|
||||
CPLineBreakByTruncatingMiddle = 5;
|
||||
|
||||
/*
|
||||
A textfield bezel with a squared corners.
|
||||
@global
|
||||
@group CPTextFieldBezelStyle
|
||||
*/
|
||||
CPTextFieldSquareBezel = 0;
|
||||
/*
|
||||
A textfield bezel with rounded corners.
|
||||
@global
|
||||
@group CPTextFieldBezelStyle
|
||||
*/
|
||||
CPTextFieldRoundedBezel = 1;
|
||||
|
||||
CPTextFieldDidFocusNotification = @"CPTextFieldDidFocusNotification";
|
||||
CPTextFieldDidBlurNotification = @"CPTextFieldDidBlurNotification";
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
@@ -87,11 +48,7 @@ var CPTextFieldDOMInputElement = nil,
|
||||
CPTextFieldInputIsActive = NO,
|
||||
CPTextFieldCachedSelectStartFunction = nil,
|
||||
CPTextFieldCachedDragFunction = nil,
|
||||
|
||||
CPTextFieldBlurFunction = nil,
|
||||
CPTextFieldKeyUpFunction = nil,
|
||||
CPTextFieldKeyPressFunction = nil,
|
||||
CPTextFieldKeyDownFunction = nil;
|
||||
CPTextFieldBlurFunction = nil;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -118,6 +75,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
*/
|
||||
@implementation CPTextField : CPControl
|
||||
{
|
||||
BOOL _isEditing;
|
||||
|
||||
BOOL _isEditable;
|
||||
BOOL _isSelectable;
|
||||
BOOL _isSecure;
|
||||
@@ -203,7 +162,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(2.0, 2.0, 2.0, 2.0), nil]
|
||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(2.0, 2.0, 2.0, 2.0), [CPNull null]]
|
||||
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
|
||||
}
|
||||
|
||||
@@ -239,80 +198,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return true;
|
||||
}
|
||||
|
||||
CPTextFieldKeyDownFunction = function(anEvent)
|
||||
{
|
||||
CPTextFieldTextDidChangeValue = [CPTextFieldInputOwner stringValue];
|
||||
|
||||
CPTextFieldKeyPressFunction(anEvent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CPTextFieldKeyPressFunction = function(aDOMEvent)
|
||||
{
|
||||
aDOMEvent = aDOMEvent || window.event;
|
||||
|
||||
if (aDOMEvent.keyCode == CPReturnKeyCode || aDOMEvent.keyCode == CPTabKeyCode)
|
||||
{
|
||||
if (aDOMEvent.preventDefault)
|
||||
aDOMEvent.preventDefault();
|
||||
if (aDOMEvent.stopPropagation)
|
||||
aDOMEvent.stopPropagation();
|
||||
aDOMEvent.cancelBubble = true;
|
||||
|
||||
var owner = CPTextFieldInputOwner;
|
||||
|
||||
if (aDOMEvent && aDOMEvent.keyCode == CPReturnKeyCode)
|
||||
{
|
||||
[owner sendAction:[owner action] to:[owner target]];
|
||||
[[owner window] makeFirstResponder:nil];
|
||||
}
|
||||
else if (aDOMEvent && aDOMEvent.keyCode == CPTabKeyCode)
|
||||
{
|
||||
if (!aDOMEvent.shiftKey)
|
||||
[[owner window] selectNextKeyView:owner];
|
||||
else
|
||||
[[owner window] selectPreviousKeyView:owner];
|
||||
}
|
||||
}
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
CPTextFieldKeyUpFunction = function()
|
||||
{
|
||||
[CPTextFieldInputOwner setStringValue:CPTextFieldDOMInputElement.value];
|
||||
|
||||
if ([CPTextFieldInputOwner stringValue] !== CPTextFieldTextDidChangeValue)
|
||||
{
|
||||
CPTextFieldTextDidChangeValue = [CPTextFieldInputOwner stringValue];
|
||||
[CPTextFieldInputOwner textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:CPTextFieldInputOwner userInfo:nil]];
|
||||
}
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
CPTextFieldHandleBlur = function(anEvent)
|
||||
{
|
||||
var owner = CPTextFieldInputOwner;
|
||||
CPTextFieldInputOwner = nil;
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
if (document.attachEvent)
|
||||
{
|
||||
CPTextFieldDOMInputElement.attachEvent("on" + CPDOMEventKeyUp, CPTextFieldKeyUpFunction);
|
||||
CPTextFieldDOMInputElement.attachEvent("on" + CPDOMEventKeyDown, CPTextFieldKeyDownFunction);
|
||||
CPTextFieldDOMInputElement.attachEvent("on" + CPDOMEventKeyPress, CPTextFieldKeyPressFunction);
|
||||
}
|
||||
else
|
||||
{
|
||||
CPTextFieldDOMInputElement.addEventListener(CPDOMEventKeyUp, CPTextFieldKeyUpFunction, NO);
|
||||
CPTextFieldDOMInputElement.addEventListener(CPDOMEventKeyDown, CPTextFieldKeyDownFunction, NO);
|
||||
CPTextFieldDOMInputElement.addEventListener(CPDOMEventKeyPress, CPTextFieldKeyPressFunction, NO);
|
||||
}
|
||||
|
||||
//FIXME make this not onblur
|
||||
CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction;
|
||||
|
||||
@@ -343,10 +235,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
CPTextFieldDOMPasswordInputElement.style.outline = "none";
|
||||
CPTextFieldDOMPasswordInputElement.type = "password";
|
||||
|
||||
CPTextFieldDOMPasswordInputElement.attachEvent("on" + CPDOMEventKeyUp, CPTextFieldKeyUpFunction);
|
||||
CPTextFieldDOMPasswordInputElement.attachEvent("on" + CPDOMEventKeyDown, CPTextFieldKeyDownFunction);
|
||||
CPTextFieldDOMPasswordInputElement.attachEvent("on" + CPDOMEventKeyPress, CPTextFieldKeyPressFunction);
|
||||
|
||||
CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurFunction;
|
||||
}
|
||||
|
||||
@@ -551,8 +439,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
/* @ignore */
|
||||
- (BOOL)becomeFirstResponder
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
if (CPTextFieldInputOwner && [CPTextFieldInputOwner window] !== [self window])
|
||||
[[CPTextFieldInputOwner window] makeFirstResponder:nil];
|
||||
#endif
|
||||
|
||||
[self setThemeState:CPThemeStateEditing];
|
||||
|
||||
@@ -560,6 +450,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
[self setNeedsLayout];
|
||||
|
||||
_isEditing = NO;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var string = [self stringValue],
|
||||
@@ -590,26 +482,25 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
window.setTimeout(function()
|
||||
{
|
||||
element.focus();
|
||||
element.focus();
|
||||
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
|
||||
CPTextFieldInputOwner = self;
|
||||
}, 0.0);
|
||||
|
||||
//post CPControlTextDidBeginEditingNotification
|
||||
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
|
||||
|
||||
element.value = [self stringValue];
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
CPTextFieldInputIsActive = YES;
|
||||
|
||||
if (document.attachEvent)
|
||||
{
|
||||
CPTextFieldCachedSelectStartFunction = document.body.onselectstart;
|
||||
CPTextFieldCachedDragFunction = document.body.ondrag;
|
||||
CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
|
||||
CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
|
||||
|
||||
document.body.ondrag = function () {};
|
||||
document.body.onselectstart = function () {};
|
||||
[[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
|
||||
[[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return YES;
|
||||
@@ -649,15 +540,32 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
CPTextFieldCachedSelectStartFunction = nil;
|
||||
CPTextFieldCachedDragFunction = nil;
|
||||
|
||||
document.body.ondrag = CPTextFieldCachedDragFunction
|
||||
document.body.onselectstart = CPTextFieldCachedSelectStartFunction
|
||||
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
|
||||
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//post CPControlTextDidEndEditingNotification
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
if (_isEditing)
|
||||
{
|
||||
_isEditing = NO;
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
|
||||
if ([self sendsActionOnEndEditing])
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
[self textDidBlur:[CPNotification notificationWithName:CPTextFieldDidBlurNotification object:self userInfo:nil]];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
Text fields require panels to become key window, so this returns \c YES.
|
||||
*/
|
||||
- (BOOL)needsPanelToBecomeKey
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -670,6 +578,89 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return [[self nextResponder] mouseDown:anEvent];
|
||||
}
|
||||
|
||||
- (void)mouseUp:(CPEvent)anEvent
|
||||
{
|
||||
if (![self isEditable] || ![self isEnabled])
|
||||
[[self nextResponder] mouseUp:anEvent];
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(CPEvent)anEvent
|
||||
{
|
||||
if (![self isEditable] || ![self isEnabled])
|
||||
[[self nextResponder] mouseDragged:anEvent];
|
||||
}
|
||||
|
||||
- (void)keyUp:(CPEvent)anEvent
|
||||
{
|
||||
var oldValue = [self stringValue];
|
||||
[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 window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
}
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
{
|
||||
if ([anEvent keyCode] === CPReturnKeyCode)
|
||||
{
|
||||
if (_isEditing)
|
||||
{
|
||||
_isEditing = NO;
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
[self selectText:nil];
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||
}
|
||||
else if ([anEvent keyCode] === CPTabKeyCode)
|
||||
{
|
||||
if ([anEvent modifierFlags] & CPShiftKeyMask)
|
||||
[[self window] selectPreviousKeyView:self];
|
||||
else
|
||||
[[self window] selectNextKeyView:self];
|
||||
|
||||
if ([[[self window] firstResponder] respondsToSelector:@selector(selectText:)])
|
||||
[[[self window] firstResponder] selectText:self];
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||
}
|
||||
else
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
|
||||
- (void)textDidBlur:(CPNotification)note
|
||||
{
|
||||
//this looks to prevent false propagation of notifications for other objects
|
||||
if([note object] != self)
|
||||
return;
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotification:note];
|
||||
}
|
||||
|
||||
- (void)textDidFocus:(CPNotification)note
|
||||
{
|
||||
//this looks to prevent false propagation of notifications for other objects
|
||||
if([note object] != self)
|
||||
return;
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotification:note];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the string the text field.
|
||||
*/
|
||||
@@ -681,9 +672,23 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (void)_setStringValue:(id)aValue
|
||||
{
|
||||
[self willChangeValueForKey:@"objectValue"];
|
||||
[super setObjectValue:String(aValue)];
|
||||
[self _updatePlaceholderState];
|
||||
[self didChangeValueForKey:@"objectValue"];
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
[super setObjectValue:aValue];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self)
|
||||
[self _inputElement].value = aValue;
|
||||
#endif
|
||||
|
||||
[self _updatePlaceholderState];
|
||||
}
|
||||
@@ -772,11 +777,151 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
#if PLATFORM(DOM)
|
||||
var element = [self _inputElement];
|
||||
|
||||
if (element.parentNode === _DOMElement && ([self isEditable] || [self isSelectable]))
|
||||
window.setTimeout(function() { element.select(); }, 0);
|
||||
if (([self isEditable] || [self isSelectable]))
|
||||
{
|
||||
if ([[self window] firstResponder] === self)
|
||||
window.setTimeout(function() { element.select(); }, 0);
|
||||
else
|
||||
{
|
||||
[[self window] makeFirstResponder:self];
|
||||
window.setTimeout(function() {[self selectText:sender];}, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)copy:(id)sender
|
||||
{
|
||||
if (![CPPlatform isBrowser])
|
||||
{
|
||||
var selectedRange = [self selectedRange];
|
||||
|
||||
if (selectedRange.length < 1)
|
||||
return;
|
||||
|
||||
var pasteboard = [CPPasteboard generalPasteboard],
|
||||
stringValue = [self stringValue],
|
||||
stringForPasting = [stringValue substringWithRange:selectedRange];
|
||||
|
||||
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
|
||||
[pasteboard setString:stringForPasting forType:CPStringPboardType];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cut:(id)sender
|
||||
{
|
||||
if (![CPPlatform isBrowser])
|
||||
{
|
||||
[self copy:sender];
|
||||
[self deleteBackward:sender];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)paste:(id)sender
|
||||
{
|
||||
if (![CPPlatform isBrowser])
|
||||
{
|
||||
var pasteboard = [CPPasteboard generalPasteboard];
|
||||
|
||||
if (![[pasteboard types] containsObject:CPStringPboardType])
|
||||
return;
|
||||
|
||||
[self deleteBackward:sender];
|
||||
|
||||
var selectedRange = [self selectedRange],
|
||||
stringValue = [self stringValue],
|
||||
pasteString = [pasteboard stringForType:CPStringPboardType],
|
||||
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
|
||||
|
||||
[self setStringValue:newValue];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location+pasteString.length, 0)];
|
||||
}
|
||||
}
|
||||
|
||||
- (CPRange)selectedRange
|
||||
{
|
||||
if ([[self window] firstResponder] !== self)
|
||||
return CPMakeRange(0, 0);
|
||||
|
||||
// we wrap this in try catch because firefox will throw an exception in certain instances
|
||||
try
|
||||
{
|
||||
var inputElement = [self _inputElement],
|
||||
selectionStart = inputElement.selectionStart,
|
||||
selectionEnd = inputElement.selectionEnd;
|
||||
|
||||
if ([selectionStart isKindOfClass:CPNumber])
|
||||
return CPMakeRange(selectionStart, selectionEnd - selectionStart);
|
||||
|
||||
// browsers which don't support selectionStart/selectionEnd (aka IE).
|
||||
var theDocument = inputElement.ownerDocument || inputElement.document,
|
||||
selectionRange = theDocument.selection.createRange(),
|
||||
range = inputElement.createTextRange();
|
||||
|
||||
if (range.inRange(selectionRange))
|
||||
{
|
||||
range.setEndPoint('EndToStart', selectionRange);
|
||||
return CPMakeRange(range.text.length, selectionRange.text.length);
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
// fall through to the return
|
||||
}
|
||||
|
||||
return CGMakeRange(0, 0);
|
||||
}
|
||||
|
||||
- (void)setSelectedRange:(CPRange)aRange
|
||||
{
|
||||
if (![[self window] firstResponder] === self)
|
||||
return;
|
||||
|
||||
var inputElement = [self _inputElement];
|
||||
|
||||
try
|
||||
{
|
||||
if ([inputElement.selectionStart isKindOfClass:CPNumber])
|
||||
{
|
||||
inputElement.selectionStart = aRange.location;
|
||||
inputElement.selectionEnd = CPMaxRange(aRange);
|
||||
}
|
||||
else
|
||||
{
|
||||
// browsers which don't support selectionStart/selectionEnd (aka IE).
|
||||
var theDocument = inputElement.ownerDocument || inputElement.document,
|
||||
existingRange = theDocument.selection.createRange(),
|
||||
range = inputElement.createTextRange();
|
||||
|
||||
if (range.inRange(existingRange))
|
||||
{
|
||||
range.collapse(true);
|
||||
range.move('character', aRange.location);
|
||||
range.moveEnd('character', aRange.length);
|
||||
range.select();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
- (void)selectAll:(id)sender
|
||||
{
|
||||
[self selectText:sender];
|
||||
}
|
||||
|
||||
- (void)deleteBackward:(id)sender
|
||||
{
|
||||
var selectedRange = [self selectedRange],
|
||||
stringValue = [self stringValue],
|
||||
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
|
||||
|
||||
[self setStringValue:newValue];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location, 0)];
|
||||
}
|
||||
|
||||
#pragma mark Setting the Delegate
|
||||
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
@@ -789,6 +934,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[defaultCenter removeObserver:_delegate name:CPControlTextDidBeginEditingNotification object:self];
|
||||
[defaultCenter removeObserver:_delegate name:CPControlTextDidChangeNotification object:self];
|
||||
[defaultCenter removeObserver:_delegate name:CPControlTextDidEndEditingNotification object:self];
|
||||
[defaultCenter removeObserver:_delegate name:CPTextFieldDidFocusNotification object:self];
|
||||
[defaultCenter removeObserver:_delegate name:CPTextFieldDidBlurNotification object:self];
|
||||
}
|
||||
|
||||
_delegate = aDelegate;
|
||||
@@ -815,6 +962,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
name:CPControlTextDidEndEditingNotification
|
||||
object:self];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(controlTextDidFocus:)])
|
||||
[defaultCenter
|
||||
addObserver:_delegate
|
||||
selector:@selector(controlTextDidFocus:)
|
||||
name:CPTextFieldDidFocusNotification
|
||||
object:self];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(controlTextDidBlur:)])
|
||||
[defaultCenter
|
||||
addObserver:_delegate
|
||||
selector:@selector(controlTextDidBlur:)
|
||||
name:CPTextFieldDidBlurNotification
|
||||
object:self];
|
||||
}
|
||||
|
||||
- (id)delegate
|
||||
@@ -878,6 +1038,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
//[view setImagePosition:CPNoImage];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -933,13 +1095,7 @@ var secureStringForString = function(aString)
|
||||
if (!aString)
|
||||
return "";
|
||||
|
||||
var secureString = "",
|
||||
length = aString.length;
|
||||
|
||||
while (length--)
|
||||
secureString += CPSecureTextFieldCharacter;
|
||||
|
||||
return secureString;
|
||||
return Array(aString.length+1).join(CPSecureTextFieldCharacter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@import <Foundation/CPKeyedUnarchiver.j>
|
||||
|
||||
var CPThemesByName = { },
|
||||
CPThemeDefaultTheme = nil;
|
||||
|
||||
+11
-17
@@ -43,7 +43,7 @@
|
||||
|
||||
if (self)
|
||||
{
|
||||
_bundle = [[CPBundle alloc] initWithPath:aURL + "/Info.plist"];
|
||||
_bundle = [[CPBundle alloc] initWithPath:aURL];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -58,27 +58,21 @@
|
||||
|
||||
- (void)bundleDidFinishLoading:(CPBundle)aBundle
|
||||
{
|
||||
var paths = [_bundle objectForInfoDictionaryKey:@"CPBundleReplacedFiles"],
|
||||
index = 0,
|
||||
count = paths.length,
|
||||
bundlePath = [_bundle bundlePath];
|
||||
|
||||
var themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"],
|
||||
count = themes.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var path = paths[count];
|
||||
|
||||
if ([path pathExtension] === "keyedtheme")
|
||||
{
|
||||
var unarchiver = [[_CPThemeKeyedUnarchiver alloc]
|
||||
initForReadingWithData:[CPData dataWithString:objj_files[bundlePath + '/' + path].contents]
|
||||
bundle:_bundle];
|
||||
var path = [aBundle pathForResource:themes[count]],
|
||||
unarchiver = [[_CPThemeKeyedUnarchiver alloc]
|
||||
initForReadingWithData:[[CPURL URLWithString:path] staticResourceData]
|
||||
bundle:_bundle];
|
||||
|
||||
[unarchiver decodeObjectForKey:@"root"];
|
||||
[unarchiver decodeObjectForKey:@"root"];
|
||||
|
||||
[unarchiver finishDecoding];
|
||||
}
|
||||
[unarchiver finishDecoding];
|
||||
}
|
||||
|
||||
|
||||
[_loadDelegate blendDidFinishLoading:self];
|
||||
}
|
||||
|
||||
|
||||
+590
-313
File diff suppressed because it is too large.
Load diff
+171
-82
@@ -26,35 +26,18 @@
|
||||
@import <AppKit/CPImage.j>
|
||||
@import <AppKit/CPView.j>
|
||||
|
||||
|
||||
/*
|
||||
@global
|
||||
@class CPToolbarItem
|
||||
*/
|
||||
CPToolbarItemVisibilityPriorityStandard = 0;
|
||||
/*
|
||||
@global
|
||||
@class CPToolbarItem
|
||||
*/
|
||||
CPToolbarItemVisibilityPriorityLow = -1000;
|
||||
/*
|
||||
@global
|
||||
@class CPToolbarItem
|
||||
*/
|
||||
CPToolbarItemVisibilityPriorityHigh = 1000;
|
||||
/*
|
||||
@global
|
||||
@class CPToolbarItem
|
||||
*/
|
||||
CPToolbarItemVisibilityPriorityUser = 2000;
|
||||
|
||||
CPToolbarSeparatorItemIdentifier = @"CPToolbarSeparatorItemIdentifier";
|
||||
CPToolbarSpaceItemIdentifier = @"CPToolbarSpaceItemIdentifier";
|
||||
CPToolbarFlexibleSpaceItemIdentifier = @"CPToolbarFlexibleSpaceItemIdentifier";
|
||||
CPToolbarShowColorsItemIdentifier = @"CPToolbarShowColorsItemIdentifier";
|
||||
CPToolbarShowFontsItemIdentifier = @"CPToolbarShowFontsItemIdentifier";
|
||||
CPToolbarCustomizeToolbarItemIdentifier = @"CPToolbarCustomizeToolbarItemIdentifier";
|
||||
CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
||||
CPToolbarSeparatorItemIdentifier = @"CPToolbarSeparatorItem";
|
||||
CPToolbarSpaceItemIdentifier = @"CPToolbarSpaceItem";
|
||||
CPToolbarFlexibleSpaceItemIdentifier = @"CPToolbarFlexibleSpaceItem";
|
||||
CPToolbarShowColorsItemIdentifier = @"CPToolbarShowColorsItem";
|
||||
CPToolbarShowFontsItemIdentifier = @"CPToolbarShowFontsItem";
|
||||
CPToolbarCustomizeToolbarItemIdentifier = @"CPToolbarCustomizeToolbarItem";
|
||||
CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -84,6 +67,13 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
||||
CGSize _maxSize;
|
||||
|
||||
int _visibilityPriority;
|
||||
|
||||
BOOL _autovalidates;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initWithItemIdentifier:@""];
|
||||
}
|
||||
|
||||
// Creating a Toolbar Item
|
||||
@@ -107,6 +97,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
||||
_maxSize = CGSizeMakeZero();
|
||||
|
||||
_visibilityPriority = CPToolbarItemVisibilityPriorityStandard;
|
||||
_autovalidates = YES;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -129,6 +120,12 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
||||
return _toolbar;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_setToolbar:(CPToolbar)aToolbar
|
||||
{
|
||||
_toolbar = aToolbar;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the item's label
|
||||
*/
|
||||
@@ -183,7 +180,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
||||
- (void)setToolTip:(CPString)aToolTip
|
||||
{
|
||||
if ([_view respondsToSelector:@selector(setToolTip:)])
|
||||
[view setToolTip:aToolTip];
|
||||
[_view setToolTip:aToolTip];
|
||||
|
||||
_toolTip = aToolTip;
|
||||
}
|
||||
@@ -308,8 +305,8 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
||||
if (!_image)
|
||||
return;
|
||||
|
||||
if (_minSize.width == 0 && _minSize.height == 0 &&
|
||||
_maxSize.width == 0 && _maxSize.height == 0)
|
||||
if (_minSize.width === 0 && _minSize.height === 0 &&
|
||||
_maxSize.width === 0 && _maxSize.height === 0)
|
||||
{
|
||||
var imageSize = [_image size];
|
||||
|
||||
@@ -388,6 +385,9 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
||||
*/
|
||||
- (void)setMinSize:(CGSize)aMinSize
|
||||
{
|
||||
if(!aMinSize.height || !aMinSize.width)
|
||||
return;
|
||||
|
||||
_minSize = CGSizeMakeCopy(aMinSize);
|
||||
|
||||
// Try to provide some sanity: Make maxSize >= minSize
|
||||
@@ -408,6 +408,9 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
||||
*/
|
||||
- (void)setMaxSize:(CGSize)aMaxSize
|
||||
{
|
||||
if(!aMaxSize.height || !aMaxSize.width)
|
||||
return;
|
||||
|
||||
_maxSize = CGSizeMakeCopy(aMaxSize);
|
||||
|
||||
// Try to provide some sanity: Make minSize <= maxSize
|
||||
@@ -444,6 +447,128 @@ CPToolbarItemVisibilityPriorityUser
|
||||
_visibilityPriority = aVisibilityPriority;
|
||||
}
|
||||
|
||||
- (void)validate
|
||||
{
|
||||
// View items do not do any target-action analysis.
|
||||
if (_view)
|
||||
{
|
||||
if ([target respondsToSelector:@selector(validateToolbarItem:)])
|
||||
[self setEnabled:[target validateToolbarItem:self]];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var action = [self action];
|
||||
|
||||
if (!action)
|
||||
return [self setEnabled:NO];
|
||||
|
||||
var target = [self target];
|
||||
|
||||
if (target && ![target respondsToSelector:action])
|
||||
return [self setEnabled:NO];
|
||||
|
||||
target = [CPApp targetForAction:action to:target from:self];
|
||||
|
||||
if (!target)
|
||||
return [self setEnabled:NO];
|
||||
|
||||
if ([target respondsToSelector:@selector(validateToolbarItem:)])
|
||||
[self setEnabled:[target validateToolbarItem:self]];
|
||||
else
|
||||
[self setEnabled:YES];
|
||||
}
|
||||
|
||||
- (BOOL)autovalidates
|
||||
{
|
||||
return _autovalidates;
|
||||
}
|
||||
|
||||
- (void)setAutovalidates:(BOOL)shouldAutovalidate
|
||||
{
|
||||
_autovalidates = !!shouldAutovalidate;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPToolbarItemItemIdentifierKey = @"CPToolbarItemItemIdentifierKey",
|
||||
CPToolbarItemLabelKey = @"CPToolbarItemLabelKey",
|
||||
CPToolbarItemPaletteLabelKey = @"CPToolbarItemPaletteLabelKey",
|
||||
CPToolbarItemToolTipKey = @"CPToolbarItemToolTipKey",
|
||||
CPToolbarItemTagKey = @"CPToolbarItemTagKey",
|
||||
CPToolbarItemTargetKey = @"CPToolbarItemTargetKey",
|
||||
CPToolbarItemActionKey = @"CPToolbarItemActionKey",
|
||||
CPToolbarItemEnabledKey = @"CPToolbarItemEnabledKey",
|
||||
CPToolbarItemImageKey = @"CPToolbarItemImageKey",
|
||||
CPToolbarItemAlternateImageKey = @"CPToolbarItemAlternateImageKey",
|
||||
CPToolbarItemViewKey = @"CPToolbarItemViewKey",
|
||||
CPToolbarItemMinSizeKey = @"CPToolbarItemMinSizeKey",
|
||||
CPToolbarItemMaxSizeKey = @"CPToolbarItemMaxSizeKey",
|
||||
CPToolbarItemVisibilityPriorityKey = @"CPToolbarItemVisibilityPriorityKey",
|
||||
CPToolbarItemAutovalidatesKey = @"CPToolbarItemAutovalidatesKey";
|
||||
|
||||
@implementation CPToolbarItem (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_itemIdentifier = [aCoder decodeObjectForKey:CPToolbarItemItemIdentifierKey];
|
||||
|
||||
_minSize = [aCoder decodeSizeForKey:CPToolbarItemMinSizeKey];
|
||||
_maxSize = [aCoder decodeSizeForKey:CPToolbarItemMaxSizeKey];
|
||||
|
||||
[self setLabel:[aCoder decodeObjectForKey:CPToolbarItemLabelKey]];
|
||||
[self setPaletteLabel:[aCoder decodeObjectForKey:CPToolbarItemPaletteLabelKey]];
|
||||
[self setToolTip:[aCoder decodeObjectForKey:CPToolbarItemToolTipKey]];
|
||||
|
||||
[self setTag:[aCoder decodeObjectForKey:CPToolbarItemTagKey]];
|
||||
[self setTarget:[aCoder decodeObjectForKey:CPToolbarItemTargetKey]];
|
||||
[self setAction:CPSelectorFromString([aCoder decodeObjectForKey:CPToolbarItemActionKey])];
|
||||
|
||||
[self setEnabled:[aCoder decodeBoolForKey:CPToolbarItemEnabledKey]];
|
||||
|
||||
[self setImage:[aCoder decodeObjectForKey:CPToolbarItemImageKey]];
|
||||
[self setAlternateImage:[aCoder decodeObjectForKey:CPToolbarItemAlternateImageKey]];
|
||||
|
||||
[self setView:[aCoder decodeObjectForKey:CPToolbarItemViewKey]];
|
||||
|
||||
[self setVisibilityPriority:[aCoder decodeIntForKey:CPToolbarItemVisibilityPriorityKey]];
|
||||
[self setAutovalidates:[aCoder decodeBoolForKey:CPToolbarItemAutovalidatesKey]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_itemIdentifier forKey:CPToolbarItemItemIdentifierKey];
|
||||
|
||||
[aCoder encodeObject:[self label] forKey:CPToolbarItemLabelKey];
|
||||
[aCoder encodeObject:[self paletteLabel] forKey:CPToolbarItemPaletteLabelKey];
|
||||
|
||||
[aCoder encodeObject:[self toolTip] forKey:CPToolbarItemToolTipKey];
|
||||
|
||||
[aCoder encodeObject:[self tag] forKey:CPToolbarItemTagKey];
|
||||
[aCoder encodeObject:[self target] forKey:CPToolbarItemTargetKey];
|
||||
[aCoder encodeObject:[self action] forKey:CPToolbarItemActionKey];
|
||||
|
||||
[aCoder encodeObject:[self isEnabled] forKey:CPToolbarItemEnabledKey];
|
||||
|
||||
[aCoder encodeObject:[self image] forKey:CPToolbarItemImageKey];
|
||||
[aCoder encodeObject:[self alternateImage] forKey:CPToolbarItemAlternateImageKey];
|
||||
|
||||
[aCoder encodeObject:[self view] forKey:CPToolbarItemViewKey];
|
||||
|
||||
[aCoder encodeSize:[self minSize] forKey:CPToolbarItemMinSizeKey];
|
||||
[aCoder encodeSize:[self maxSize] forKey:CPToolbarItemMaxSizeKey];
|
||||
|
||||
[aCoder encodeObject:[self visibilityPriority] forKey:CPToolbarItemVisibilityPriorityKey];
|
||||
[aCoder encodeBool:[self autovalidates] forKey:CPToolbarItemAutovalidatesKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPToolbarItem (CPCopying)
|
||||
@@ -451,10 +576,12 @@ CPToolbarItemVisibilityPriorityUser
|
||||
- (id)copy
|
||||
{
|
||||
var copy = [[[self class] alloc] initWithItemIdentifier:_itemIdentifier];
|
||||
|
||||
|
||||
if (_view)
|
||||
[copy setView:[CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:_view]]];
|
||||
|
||||
|
||||
[copy _setToolbar:_toolbar];
|
||||
|
||||
[copy setLabel:_label];
|
||||
[copy setPaletteLabel:_paletteLabel];
|
||||
[copy setToolTip:[self toolTip]];
|
||||
@@ -462,7 +589,7 @@ CPToolbarItemVisibilityPriorityUser
|
||||
[copy setTag:[self tag]];
|
||||
[copy setTarget:[self target]];
|
||||
[copy setAction:[self action]];
|
||||
|
||||
|
||||
[copy setEnabled:[self isEnabled]];
|
||||
|
||||
[copy setImage:[self image]];
|
||||
@@ -470,9 +597,10 @@ CPToolbarItemVisibilityPriorityUser
|
||||
|
||||
[copy setMinSize:_minSize];
|
||||
[copy setMaxSize:_maxSize];
|
||||
|
||||
[copy setVisibilityPriority:_visibilityPriority];
|
||||
|
||||
|
||||
[copy setVisibilityPriority:[self visibilityPriority]];
|
||||
[copy setAutovalidates:[self autovalidates]];
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
@@ -480,62 +608,17 @@ CPToolbarItemVisibilityPriorityUser
|
||||
|
||||
// Standard toolbar identifiers
|
||||
|
||||
var _CPToolbarSeparatorItemView = nil,
|
||||
_CPToolbarSpaceItemView = nil;
|
||||
|
||||
@implementation CPToolbarItem (Standard)
|
||||
|
||||
+ (CPView)_separatorItemView
|
||||
{
|
||||
if (!_CPToolbarSeparatorItemView)
|
||||
{
|
||||
_CPToolbarSeparatorItemView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 2.0, 32.0)];
|
||||
|
||||
sizes = {};
|
||||
sizes[@"CPToolbarItemSeparator"] = [CGSizeMake(2.0, 26.0), CGSizeMake(2.0, 1.0), CGSizeMake(2.0, 26.0)];
|
||||
[_CPToolbarSeparatorItemView setBackgroundColor:_CPControlThreePartImagePattern(YES, sizes, @"CPToolbarItem", @"Separator")];
|
||||
}
|
||||
|
||||
return _CPToolbarSeparatorItemView;
|
||||
}
|
||||
|
||||
+ (CPView)_spaceItemView
|
||||
{
|
||||
if (!_CPToolbarSpaceItemView)
|
||||
_CPToolbarSpaceItemView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
return _CPToolbarSpaceItemView;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
+ (CPToolbarItem)_standardItemWithItemIdentifier:(CPString)anItemIdentifier
|
||||
{
|
||||
var item = [[CPToolbarItem alloc] initWithItemIdentifier:anItemIdentifier];
|
||||
|
||||
switch (anItemIdentifier)
|
||||
{
|
||||
case CPToolbarSeparatorItemIdentifier: [item setView:[self _separatorItemView]];
|
||||
|
||||
[item setMinSize:CGSizeMake(2.0, 0.0)];
|
||||
[item setMaxSize:CGSizeMake(2.0, 100000.0)];
|
||||
|
||||
return item;
|
||||
|
||||
case CPToolbarSpaceItemIdentifier: [item setView:[self _spaceItemView]];
|
||||
|
||||
[item setMinSize:CGSizeMake(32.0, 32.0)];
|
||||
[item setMaxSize:CGSizeMake(32.0, 32.0)];
|
||||
|
||||
return item;
|
||||
|
||||
case CPToolbarFlexibleSpaceItemIdentifier: [item setView:[self _spaceItemView]];
|
||||
|
||||
[item setMinSize:CGSizeMake(32.0, 32.0)];
|
||||
[item setMaxSize:CGSizeMake(10000.0, 32.0)];
|
||||
|
||||
return item;
|
||||
|
||||
case CPToolbarShowColorsItemIdentifier: return nil;
|
||||
case CPToolbarSeparatorItemIdentifier: return [_CPToolbarSeparatorItem new];
|
||||
case CPToolbarSpaceItemIdentifier: return [_CPToolbarSpaceItem new];
|
||||
case CPToolbarFlexibleSpaceItemIdentifier: return [_CPToolbarFlexibleSpaceItem new];
|
||||
case CPToolbarShowColorsItemIdentifier: return [_CPToolbarShowColorsItem new];
|
||||
case CPToolbarShowFontsItemIdentifier: return nil;
|
||||
case CPToolbarCustomizeToolbarItemIdentifier: return nil;
|
||||
case CPToolbarPrintItemIdentifier: return nil;
|
||||
@@ -545,3 +628,9 @@ var _CPToolbarSeparatorItemView = nil,
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@import "_CPToolbarFlexibleSpaceItem.j"
|
||||
@import "_CPToolbarShowColorsItem.j"
|
||||
@import "_CPToolbarSeparatorItem.j"
|
||||
@import "_CPToolbarSpaceItem.j"
|
||||
|
||||
+46
-9
@@ -7,7 +7,7 @@
|
||||
id _representedObject @accessors(readonly, property=representedObject);
|
||||
|
||||
CPTreeNode _parentNode @accessors(readonly, property=parentNode);
|
||||
CPMutableArray _childNodes @accessors(readonly, property=childNodes);
|
||||
CPMutableArray _childNodes;
|
||||
}
|
||||
|
||||
+ (id)treeNodeWithRepresentedObject:(id)anObject
|
||||
@@ -33,32 +33,40 @@
|
||||
return [_childNodes count] <= 0;
|
||||
}
|
||||
|
||||
- (CPArray)childNodes
|
||||
{
|
||||
return [_childNodes copy];
|
||||
}
|
||||
|
||||
- (CPMutableArray)mutableChildNodes
|
||||
{
|
||||
return [self mutableArrayValueForKey:@"childNodes"];
|
||||
}
|
||||
|
||||
- (void)insertObject:(id)anObject inChildNodesAtIndex:(CPInteger)anIndex
|
||||
- (void)insertObject:(id)aTreeNode inChildNodesAtIndex:(CPInteger)anIndex
|
||||
{
|
||||
anObject._parentNode = self;
|
||||
[[aTreeNode._parentNode mutableChildNodes] removeObjectIdenticalTo:aTreeNode];
|
||||
|
||||
[_childNodes addObject:anObject];
|
||||
aTreeNode._parentNode = self;
|
||||
|
||||
[_childNodes insertObject:aTreeNode atIndex:anIndex];
|
||||
}
|
||||
|
||||
- (void)removeObjectFromChildNodesAtIndex:(CPInteger)anIndex
|
||||
{
|
||||
anObject._parentNode = nil;
|
||||
[_childNodes objectAtIndex:anIndex]._parentNode = nil;
|
||||
|
||||
[_childNodes removeObjectAtIndex:anIndex];
|
||||
}
|
||||
|
||||
- (void)replaceObjectFromChildNodesAtIndex:(CPInteger)anIndex withObject:(id)anObject
|
||||
- (void)replaceObjectFromChildNodesAtIndex:(CPInteger)anIndex withObject:(id)aTreeNode
|
||||
{
|
||||
var oldObject = [_childNodes objectAtIndex:anIndex];
|
||||
var oldTreeNode = [_childNodes objectAtIndex:anIndex];
|
||||
|
||||
oldObject._parentNode = nil;
|
||||
oldTreeNode._parentNode = nil;
|
||||
aTreeNode._parentNode = self;
|
||||
|
||||
[_childNodes replaceObjectAtIndex:anIndex withObject:anObject];
|
||||
[_childNodes replaceObjectAtIndex:anIndex withObject:aTreeNode];
|
||||
}
|
||||
|
||||
- (id)objectInChildNodesAtIndex:(CPInteger)anIndex
|
||||
@@ -80,3 +88,32 @@
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
|
||||
CPTreeNodeParentNodeKey = @"CPTreeNodeParentNodeKey",
|
||||
CPTreeNodeChildNodesKey = @"CPTreeNodeChildNodesKey";
|
||||
|
||||
@implementation CPTreeNode (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_representedObject = [aCoder decodeObjectForKey:CPTreeNodeRepresentedObjectKey];
|
||||
_parentNode = [aCoder decodeObjectForKey:CPTreeNodeParentNodeKey];
|
||||
_childNodes = [aCoder decodeObjectForKey:CPTreeNodeChildNodesKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_representedObject forKey:CPTreeNodeRepresentedObjectKey];
|
||||
[aCoder encodeConditionalObject:_parentNode forKey:CPTreeNodeParentNodeKey];
|
||||
[aCoder encodeObject:_childNodes forKey:CPTreeNodeChildNodesKey];
|
||||
}
|
||||
|
||||
@end
|
||||
+186
-34
@@ -238,6 +238,16 @@ var CPViewFlags = { },
|
||||
return [CPSet setWithObjects:@"frameOrigin", @"frameSize"];
|
||||
}
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingBounds
|
||||
{
|
||||
return [CPSet setWithObjects:@"boundsOrigin", @"boundsSize"];
|
||||
}
|
||||
|
||||
+ (CPMenu)defaultMenu
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initWithFrame:CGRectMakeZero()];
|
||||
@@ -308,7 +318,7 @@ var CPViewFlags = { },
|
||||
*/
|
||||
- (CPArray)subviews
|
||||
{
|
||||
return _subviews;
|
||||
return [_subviews copy];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -441,7 +451,7 @@ var CPViewFlags = { },
|
||||
|
||||
[_superview willRemoveSubview:self];
|
||||
|
||||
[[_superview subviews] removeObject:self];
|
||||
[_superview._subviews removeObject:self];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
CPDOMDisplayServerRemoveChild(_superview._DOMElement, _DOMElement);
|
||||
@@ -468,6 +478,75 @@ var CPViewFlags = { },
|
||||
[self _insertSubview:aView atIndex:index];
|
||||
}
|
||||
|
||||
- (void)setSubviews:(CPArray)newSubviews
|
||||
{
|
||||
if (!newSubviews)
|
||||
[CPException raise:CPInvalidArgumentException reason:"newSubviews cannot be nil in -[CPView setSubviews:]"];
|
||||
|
||||
// Trivial Case 0: Same array somehow
|
||||
if ([_subviews isEqual:newSubviews])
|
||||
return;
|
||||
|
||||
// Trivial Case 1: No current subviews, simply add all new subviews.
|
||||
if ([_subviews count] === 0)
|
||||
{
|
||||
var index = 0,
|
||||
count = [newSubviews count];
|
||||
|
||||
for (; index < count; ++index)
|
||||
[self addSubview:newSubviews[index]];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Trivial Case 2: No new subviews, simply remove all current subviews.
|
||||
if ([newSubviews count] === 0)
|
||||
{
|
||||
var count = [_subviews count];
|
||||
|
||||
while (count--)
|
||||
[_subviews[count] removeFromSuperview];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Find out the views that were removed.
|
||||
var removedSubviews = [CPMutableSet setWithArray:_subviews];
|
||||
|
||||
[removedSubviews removeObjectsInArray:newSubviews];
|
||||
[removedSubviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
|
||||
// Find out which views need to be added.
|
||||
var addedSubviews = [CPMutableSet setWithArray:newSubviews];
|
||||
|
||||
[addedSubviews removeObjectsInArray:_subviews];
|
||||
|
||||
var addedSubview = nil,
|
||||
addedSubviewEnumerator = [addedSubviews objectEnumerator];
|
||||
|
||||
while (addedSubview = [addedSubviewEnumerator nextObject])
|
||||
[self addSubview:addedSubview];
|
||||
|
||||
// If the order is fine, no need to reorder.
|
||||
if ([_subviews isEqual:newSubviews])
|
||||
return;
|
||||
|
||||
_subviews = [newSubviews copy];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
var index = 0,
|
||||
count = [_subviews count];
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var subview = _subviews[index];
|
||||
|
||||
CPDOMDisplayServerRemoveChild(_DOMElement, subview._DOMElement);
|
||||
CPDOMDisplayServerAppendChild(_DOMElement, subview._DOMElement);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_setWindow:(CPWindow)aWindow
|
||||
{
|
||||
@@ -594,9 +673,9 @@ var CPViewFlags = { },
|
||||
return _tag;
|
||||
}
|
||||
|
||||
- (void)viewWithTag:(CPInteger)aTag
|
||||
- (CPView)viewWithTag:(CPInteger)aTag
|
||||
{
|
||||
if ([self tag] === aTag)
|
||||
if ([self tag] == aTag)
|
||||
return self;
|
||||
|
||||
var index = 0,
|
||||
@@ -816,6 +895,16 @@ var CPViewFlags = { },
|
||||
return _CGRectMakeCopy(_bounds);
|
||||
}
|
||||
|
||||
- (CGPoint)boundsOrigin
|
||||
{
|
||||
return _CGPointMakeCopy(_bounds.origin);
|
||||
}
|
||||
|
||||
- (CGSize)boundsSize
|
||||
{
|
||||
return _CGSizeMakeCopy(_bounds.size);
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the location of the receiver inside its frame. The method
|
||||
posts a CPViewBoundsDidChangeNotification to the
|
||||
@@ -1115,7 +1204,7 @@ var CPViewFlags = { },
|
||||
|
||||
if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature))
|
||||
{
|
||||
if (anAlphaValue == 1.0)
|
||||
if (anAlphaValue === 1.0)
|
||||
try { _DOMElement.style.removeAttribute("filter") } catch (anException) { }
|
||||
else
|
||||
_DOMElement.style.filter = "alpha(opacity=" + anAlphaValue * 100 + ")";
|
||||
@@ -1202,6 +1291,14 @@ var CPViewFlags = { },
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \c YES if this view requires a panel to become key. Normally only text fields, so this returns \c NO.
|
||||
*/
|
||||
- (BOOL)needsPanelToBecomeKey
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \c YES if mouse events aren't needed by the receiver and can be sent to the superview. The
|
||||
default implementation returns \c NO if the view is opaque.
|
||||
@@ -1217,6 +1314,22 @@ var CPViewFlags = { },
|
||||
[super mouseDown:anEvent];
|
||||
}
|
||||
|
||||
- (void)rightMouseDown:(CPEvent)anEvent
|
||||
{
|
||||
var menu = [self menuForEvent:anEvent];
|
||||
if (menu)
|
||||
[CPMenu popUpContextMenu:menu withEvent:anEvent forView:self];
|
||||
else if ([[self nextResponder] isKindOfClass:CPView])
|
||||
[super rightMouseDown:anEvent];
|
||||
else
|
||||
[[[anEvent window] platformWindow] _propagateContextMenuDOMEvent:YES];
|
||||
}
|
||||
|
||||
- (CPMenu)menuForEvent:(CPEvent)anEvent
|
||||
{
|
||||
return [self menu] || [[self class] defaultMenu];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the background color of the receiver.
|
||||
@param aColor the new color for the receiver's background
|
||||
@@ -1225,56 +1338,72 @@ var CPViewFlags = { },
|
||||
{
|
||||
if (_backgroundColor == aColor)
|
||||
return;
|
||||
|
||||
|
||||
_backgroundColor = aColor;
|
||||
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
var patternImage = [_backgroundColor patternImage],
|
||||
colorExists = _backgroundColor && ([_backgroundColor patternImage] || [_backgroundColor alphaComponent] > 0.0),
|
||||
colorHasAlpha = colorExists && [_backgroundColor alphaComponent] < 1.0,
|
||||
supportsRGBA = CPFeatureIsCompatible(CPCSSRGBAFeature),
|
||||
colorNeedsDOMElement = colorHasAlpha && !supportsRGBA,
|
||||
amount = 0;
|
||||
|
||||
|
||||
if ([patternImage isThreePartImage])
|
||||
{
|
||||
_backgroundType = [patternImage isVertical] ? BackgroundVerticalThreePartImage : BackgroundHorizontalThreePartImage;
|
||||
|
||||
amount = 3 - _DOMImageParts.length;
|
||||
}
|
||||
else if ([patternImage isNinePartImage])
|
||||
{
|
||||
_backgroundType = BackgroundNinePartImage;
|
||||
|
||||
amount = 9 - _DOMImageParts.length;
|
||||
amount = 9 - _DOMImageParts.length;
|
||||
}
|
||||
else
|
||||
{
|
||||
_backgroundType = BackgroundTrivialColor;
|
||||
|
||||
amount = 0 - _DOMImageParts.length;
|
||||
amount = (colorNeedsDOMElement ? 1 : 0) - _DOMImageParts.length;
|
||||
}
|
||||
|
||||
if (amount > 0)
|
||||
{
|
||||
while (amount--)
|
||||
{
|
||||
var DOMElement = DOMElementPrototype.cloneNode(false);
|
||||
|
||||
|
||||
DOMElement.style.zIndex = -1000;
|
||||
|
||||
|
||||
_DOMImageParts.push(DOMElement);
|
||||
_DOMElement.appendChild(DOMElement);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
amount = -amount;
|
||||
|
||||
while (amount--)
|
||||
_DOMElement.removeChild(_DOMImageParts.pop());
|
||||
}
|
||||
|
||||
if (_backgroundType == BackgroundTrivialColor)
|
||||
|
||||
// Opera doesn't like DOM properties set to nil.
|
||||
// https://trac.280north.com/ticket/7
|
||||
_DOMElement.style.background = _backgroundColor ? [_backgroundColor cssString] : "";
|
||||
|
||||
|
||||
if (_backgroundType === BackgroundTrivialColor)
|
||||
{
|
||||
var colorCSS = colorExists ? [_backgroundColor cssString] : "";
|
||||
|
||||
if (colorNeedsDOMElement)
|
||||
{
|
||||
_DOMElement.style.background = "";
|
||||
_DOMImageParts[0].style.background = [_backgroundColor cssString];
|
||||
|
||||
if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature))
|
||||
_DOMImageParts[0].style.filter = "alpha(opacity=" + [_backgroundColor alphaComponent] * 100 + ")";
|
||||
else
|
||||
_DOMImageParts[0].style.opacity = [_backgroundColor alphaComponent];
|
||||
|
||||
var size = [self bounds].size;
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], size.width, size.height);
|
||||
}
|
||||
else
|
||||
_DOMElement.style.background = colorCSS;
|
||||
}
|
||||
else
|
||||
{
|
||||
var slices = [patternImage imageSlices],
|
||||
@@ -1285,23 +1414,31 @@ var CPViewFlags = { },
|
||||
{
|
||||
var image = slices[count],
|
||||
size = _DOMImageSizes[count] = image ? [image size] : _CGSizeMakeZero();
|
||||
|
||||
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[count], size.width, size.height);
|
||||
|
||||
_DOMImageParts[count].style.background = image ? "url(\"" + [image filename] + "\")" : "";
|
||||
|
||||
if (!supportsRGBA)
|
||||
{
|
||||
if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature))
|
||||
try { _DOMImageParts[count].style.removeAttribute("filter") } catch (anException) { }
|
||||
else
|
||||
_DOMImageParts[count].style.opacity = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_backgroundType == BackgroundNinePartImage)
|
||||
{
|
||||
var width = frameSize.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width,
|
||||
height = frameSize.height - _DOMImageSizes[0].height - _DOMImageSizes[6].height;
|
||||
|
||||
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], width, _DOMImageSizes[0].height);
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[3], _DOMImageSizes[3].width, height);
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[4], width, height);
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[5], _DOMImageSizes[5].width, height);
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[7], width, _DOMImageSizes[7].height);
|
||||
|
||||
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0);
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0);
|
||||
CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[2], NULL, 0.0, 0.0);
|
||||
@@ -1315,7 +1452,7 @@ var CPViewFlags = { },
|
||||
else if (_backgroundType == BackgroundVerticalThreePartImage)
|
||||
{
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width, frameSize.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height);
|
||||
|
||||
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0);
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, 0.0, _DOMImageSizes[0].height);
|
||||
CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[2], NULL, 0.0, 0.0);
|
||||
@@ -1323,7 +1460,7 @@ var CPViewFlags = { },
|
||||
else if (_backgroundType == BackgroundHorizontalThreePartImage)
|
||||
{
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, frameSize.height);
|
||||
|
||||
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0);
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0);
|
||||
CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[2], NULL, 0.0, 0.0);
|
||||
@@ -1666,8 +1803,9 @@ setBoundsOrigin:
|
||||
_DOMContentsElement.style.width = ROUND(_CGRectGetWidth(_frame)) + "px";
|
||||
_DOMContentsElement.style.height = ROUND(_CGRectGetHeight(_frame)) + "px";
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
CPDOMDisplayServerAppendChild(_DOMElement, _DOMContentsElement);
|
||||
|
||||
#endif
|
||||
_graphicsContext = [CPGraphicsContext graphicsContextWithGraphicsPort:graphicsPort flipped:YES];
|
||||
}
|
||||
|
||||
@@ -1861,6 +1999,18 @@ setBoundsOrigin:
|
||||
|
||||
@implementation CPView (KeyView)
|
||||
|
||||
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
|
||||
{
|
||||
var count = [_subviews count];
|
||||
|
||||
// Is reverse iteration correct here? It matches the other (correct) code like hit testing.
|
||||
while (count--)
|
||||
if ([_subviews[count] performKeyEquivalent:anEvent])
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeKeyView
|
||||
{
|
||||
return [self acceptsFirstResponder] && ![self isHiddenOrHasHiddenAncestor];
|
||||
@@ -2033,7 +2183,8 @@ setBoundsOrigin:
|
||||
|
||||
var theClass = [self class],
|
||||
CPViewClass = [CPView class],
|
||||
attributes = [];
|
||||
attributes = [],
|
||||
nullValue = [CPNull null];
|
||||
|
||||
for (; theClass && theClass !== CPViewClass; theClass = [theClass superclass])
|
||||
{
|
||||
@@ -2057,9 +2208,10 @@ setBoundsOrigin:
|
||||
|
||||
while (attributeCount--)
|
||||
{
|
||||
var attributeName = attributeKeys[attributeCount];
|
||||
var attributeName = attributeKeys[attributeCount],
|
||||
attributeValue = [attributeDictionary objectForKey:attributeName];
|
||||
|
||||
attributes.push([attributeDictionary objectForKey:attributeName]);
|
||||
attributes.push(attributeValue === nullValue ? nil : attributeValue);
|
||||
attributes.push(attributeName);
|
||||
}
|
||||
}
|
||||
@@ -2187,7 +2339,7 @@ setBoundsOrigin:
|
||||
return [_themeAttributes[aName] value];
|
||||
}
|
||||
|
||||
- (void)currentValueForThemeAttribute:(CPString)aName
|
||||
- (id)currentValueForThemeAttribute:(CPString)aName
|
||||
{
|
||||
if (!_themeAttributes || !_themeAttributes[aName])
|
||||
[CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"];
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* CPFlashView.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Klaas Pieter Annema on September 3, 2009.
|
||||
* Copyright 2009, Sofa BV
|
||||
*
|
||||
* 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 <AppKit/CPAnimation.j>
|
||||
|
||||
CPViewAnimationTargetKey = @"CPViewAnimationTarget";
|
||||
CPViewAnimationStartFrameKey = @"CPViewAnimationStartFrame";
|
||||
CPViewAnimationEndFrameKey = @"CPViewAnimationEndFrame";
|
||||
CPViewAnimationEffectKey = @"CPViewAnimationEffect";
|
||||
|
||||
CPViewAnimationFadeInEffect = @"CPViewAnimationFadeIn";
|
||||
CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
|
||||
|
||||
@implementation CPViewAnimation : CPAnimation
|
||||
{
|
||||
CPArray _viewAnimations;
|
||||
}
|
||||
|
||||
- (id)initWithViewAnimations:(CPArray)viewAnimations
|
||||
{
|
||||
if (self = [super initWithDuration:0.5 animationCurve:CPAnimationLinear])
|
||||
{
|
||||
[self setViewAnimations:viewAnimations];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)startAnimation
|
||||
{
|
||||
var animationIndex = [_viewAnimations count];
|
||||
while (animationIndex--)
|
||||
{
|
||||
var dictionary = [_viewAnimations objectAtIndex:animationIndex],
|
||||
view = [self _targetView:dictionary],
|
||||
startFrame = [self _startFrame:dictionary];
|
||||
|
||||
[view setFrame:startFrame];
|
||||
|
||||
var effect = [self _effect:dictionary];
|
||||
if (effect === CPViewAnimationFadeInEffect)
|
||||
{
|
||||
[view setAlphaValue:0.0];
|
||||
[view setHidden:NO];
|
||||
}
|
||||
else if (effect === CPViewAnimationFadeOutEffect)
|
||||
[view setAlphaValue:1.0];
|
||||
}
|
||||
|
||||
[super startAnimation];
|
||||
}
|
||||
|
||||
- (void)setCurrentProgress:(NSAnimationProgress)progress
|
||||
{
|
||||
[super setCurrentProgress:progress];
|
||||
|
||||
var animationIndex = [_viewAnimations count];
|
||||
while (animationIndex--)
|
||||
{
|
||||
var dictionary = [_viewAnimations objectAtIndex:animationIndex],
|
||||
view = [self _targetView:dictionary]
|
||||
startFrame = [self _startFrame:dictionary]
|
||||
endFrame = [self _endFrame:dictionary]
|
||||
differenceFrame = CPRectMakeZero();
|
||||
|
||||
differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x;
|
||||
differenceFrame.origin.y = endFrame.origin.y - startFrame.origin.y;
|
||||
differenceFrame.size.width = endFrame.size.width - startFrame.size.width;
|
||||
differenceFrame.size.height = endFrame.size.height - startFrame.size.height;
|
||||
|
||||
var intermediateFrame = CPRectMakeZero();
|
||||
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;
|
||||
|
||||
[view setFrame:intermediateFrame];
|
||||
|
||||
// Update the view's alpha value
|
||||
var effect = [self _effect:dictionary];
|
||||
if (effect === CPViewAnimationFadeInEffect)
|
||||
[view setAlphaValue:1.0 * progress];
|
||||
else if (effect === CPViewAnimationFadeOutEffect)
|
||||
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress];
|
||||
|
||||
if (progress === 1.0)
|
||||
[view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopAnimation
|
||||
{
|
||||
var animationIndex = [_viewAnimations count];
|
||||
while (animationIndex--)
|
||||
{
|
||||
var dictionary = [_viewAnimations objectAtIndex:animationIndex],
|
||||
view = [self _targetView:dictionary],
|
||||
endFrame = [self _endFrame:dictionary];
|
||||
|
||||
[view setFrame:endFrame];
|
||||
|
||||
var effect = [self _effect:dictionary];
|
||||
if (effect === CPViewAnimationFadeInEffect)
|
||||
[view setAlphaValue:1.0];
|
||||
else if (effect === CPViewAnimationFadeOutEffect)
|
||||
[view setAlphaValue:0.0];
|
||||
|
||||
[view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0];
|
||||
}
|
||||
|
||||
[super stopAnimation];
|
||||
}
|
||||
|
||||
- (id)_targetView:(CPDictionary)dictionary
|
||||
{
|
||||
var targetView = [dictionary valueForKey:CPViewAnimationTargetKey];
|
||||
if (!targetView)
|
||||
[CPException raise:CPInternalInconsistencyException reason:[CPString stringWithFormat:@"view animation: %@ does not have a target view", [dictionary description]]];
|
||||
|
||||
return targetView;
|
||||
}
|
||||
|
||||
- (CPRect)_startFrame:(CPDictionary)dictionary
|
||||
{
|
||||
var startFrame = [dictionary valueForKey:CPViewAnimationStartFrameKey];
|
||||
if (!startFrame)
|
||||
return [[self _targetView:dictionary] frame];
|
||||
|
||||
return startFrame;
|
||||
}
|
||||
|
||||
- (CPRect)_endFrame:(CPDictionary)dictionary
|
||||
{
|
||||
var endFrame = [dictionary valueForKey:CPViewAnimationEndFrameKey];
|
||||
if (!endFrame)
|
||||
return [[self _targetView:dictionary] frame];
|
||||
|
||||
return endFrame;
|
||||
}
|
||||
|
||||
- (CPString)_effect:(CPDictionary)dictionary
|
||||
{
|
||||
return [dictionary valueForKey:CPViewAnimationEffectKey];
|
||||
}
|
||||
|
||||
- (CPArray)viewAnimations
|
||||
{
|
||||
return _viewAnimations;
|
||||
}
|
||||
|
||||
- (void)setViewAnimations:(CPArray)viewAnimations
|
||||
{
|
||||
if (viewAnimations != _viewAnimations)
|
||||
{
|
||||
[self stopAnimation];
|
||||
_viewAnimations = [viewAnimations copy];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
+54
-14
@@ -22,6 +22,7 @@
|
||||
|
||||
@import <AppKit/CPResponder.j>
|
||||
|
||||
var CPViewControllerCachedCibs;
|
||||
|
||||
/*! @class CPViewController
|
||||
The CPViewController class provides the fundamental view-management controller for Cappuccino applications.
|
||||
@@ -31,7 +32,7 @@
|
||||
|
||||
You use each instance of CPViewController to manage a single view (and hierarchy). For a simple view controller,
|
||||
this entails managing the view hierarchy responsible for presenting your application content.
|
||||
A typical view hierarchy consists of a root viewÑa reference to which is available in the view property of this classÑ
|
||||
A typical view hierarchy consists of a root viewŃa reference to which is available in the view property of this classŃ
|
||||
and one or more subviews presenting the actual content. In the case of navigation and tab bar controllers, the view
|
||||
controller manages not only the high-level view hierarchy (which provides the navigation controls) but also one
|
||||
or more additional view controllers that handle the presentation of the application content.
|
||||
@@ -56,6 +57,12 @@
|
||||
CPDictionary _cibExternalNameTable @accessors(property=cibExternalNameTable, readonly);
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self === CPViewController)
|
||||
CPViewControllerCachedCibs = [CPDictionary dictionary];
|
||||
}
|
||||
|
||||
/*!
|
||||
Convenience initializer calls -initWithCibName:bundle: with nil for both parameters.
|
||||
*/
|
||||
@@ -104,8 +111,8 @@
|
||||
If you create your views manually, you must override this method and use it to create your view and assign it to the view property.
|
||||
The default implementation for programmatic views is to create a plain view. You can invoke super to utilize this view.
|
||||
|
||||
If you use Interface Builder to create your views and initialize the view controllerÑthat is, you initialize the view using the
|
||||
initWithCibName:bundle: methodÑthen you must not override this method. The consequences risk shattering the space-time continuum.
|
||||
If you use Interface Builder to create your views and initialize the view controllerŃthat is, you initialize the view using the
|
||||
initWithCibName:bundle: methodŃthen you must not override this method. The consequences risk shattering the space-time continuum.
|
||||
|
||||
Note: The cib loading system is currently asynchronous.
|
||||
*/
|
||||
@@ -113,11 +120,16 @@
|
||||
{
|
||||
if (_view)
|
||||
return;
|
||||
|
||||
// check if a cib is already cached for the current _cibName
|
||||
var cib = [CPViewControllerCachedCibs objectForKey:_cibName];
|
||||
|
||||
// if (_cibName)
|
||||
// [CPException raise: reason:];
|
||||
|
||||
var cib = [[CPCib alloc] initWithContentsOfURL:[_cibBundle pathForResource:_cibName + @".cib"]];
|
||||
if (!cib)
|
||||
{
|
||||
// if the cib isn't cached yet : fetch it and cache it
|
||||
cib = [[CPCib alloc] initWithContentsOfURL:[_cibBundle pathForResource:_cibName + @".cib"]];
|
||||
[CPViewControllerCachedCibs setObject:cib forKey:_cibName];
|
||||
}
|
||||
|
||||
[cib instantiateCibWithExternalNameTable:_cibExternalNameTable];
|
||||
}
|
||||
@@ -126,8 +138,6 @@
|
||||
Returns the view that the controller manages.
|
||||
If this property is nil, the controller sends loadView to itself to create the view that it manages.
|
||||
Subclasses should override the loadView method to create any custom views. The default value is nil.
|
||||
|
||||
Note: An error will not be thrown if after -loadView, the view property is still nil. -view will simply return nil, but will continue to call -loadView on subsequent calls.
|
||||
*/
|
||||
- (CPView)view
|
||||
{
|
||||
@@ -143,14 +153,34 @@
|
||||
if (_view === nil && [cibOwner isKindOfClass:[CPDocument class]])
|
||||
[self setView:[cibOwner valueForKey:@"view"]];
|
||||
|
||||
if (!_view)
|
||||
{
|
||||
var reason = [CPString stringWithFormat:@"View for %@ could not be loaded from Cib or no view specified. Override loadView to load the view manually.", self];
|
||||
|
||||
[CPException raise:CPInternalInconsistencyException reason:reason];
|
||||
}
|
||||
|
||||
if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)])
|
||||
[cibOwner viewControllerDidLoadCib:self];
|
||||
|
||||
[self viewDidLoad];
|
||||
}
|
||||
|
||||
return _view;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
This method is called after the view controller has loaded its associated views into memory.
|
||||
This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method.
|
||||
This method is most commonly used to perform additional initialization steps on views that are loaded from nib files.
|
||||
*/
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Manually sets the view that the controller manages.
|
||||
Setting to nil will cause -loadView to be called on all subsequent calls of -view.
|
||||
@@ -166,14 +196,16 @@
|
||||
|
||||
|
||||
var CPViewControllerViewKey = @"CPViewControllerViewKey",
|
||||
CPViewControllerTitleKey = @"CPViewControllerTitleKey";
|
||||
CPViewControllerTitleKey = @"CPViewControllerTitleKey",
|
||||
CPViewControllerCibNameKey = @"CPViewControllerCibNameKey",
|
||||
CPViewControllerBundleKey = @"CPViewControllerBundleKey";
|
||||
|
||||
@implementation CPViewController (CPCoding)
|
||||
|
||||
/*!
|
||||
Initializes the view item by unarchiving data from a coder.
|
||||
Initializes the view controller by unarchiving data from a coder.
|
||||
@param aCoder the coder from which the data will be unarchived
|
||||
@return the initialized collection view item
|
||||
@return the initialized view controller
|
||||
*/
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
@@ -183,14 +215,20 @@ var CPViewControllerViewKey = @"CPViewControllerViewKey",
|
||||
{
|
||||
_view = [aCoder decodeObjectForKey:CPViewControllerViewKey];
|
||||
_title = [aCoder decodeObjectForKey:CPViewControllerTitleKey];
|
||||
_cibName = [aCoder decodeObjectForKey:CPViewControllerCibNameKey];
|
||||
|
||||
var bundlePath = [aCoder decodeObjectForKey:CPViewControllerBundleKey];
|
||||
_cibBundle = bundlePath ? [CPBundle bundleWithPath:bundlePath] : [CPBundle mainBundle];
|
||||
|
||||
_cibExternalNameTable = [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Archives the colletion view item to the provided coder.
|
||||
@param aCoder the coder to which the view item should be archived
|
||||
Archives the view controller to the provided coder.
|
||||
@param aCoder the coder to which the view controller should be archived
|
||||
*/
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
@@ -198,6 +236,8 @@ var CPViewControllerViewKey = @"CPViewControllerViewKey",
|
||||
|
||||
[aCoder encodeObject:_view forKey:CPViewControllerViewKey];
|
||||
[aCoder encodeObject:_title forKey:CPViewControllerTitleKey];
|
||||
[aCoder encodeObject:_cibName forKey:CPViewControllerCibNameKey];
|
||||
[aCoder encodeObject:[_cibBundle bundlePath] forKey:CPViewControllerBundleKey];
|
||||
}
|
||||
|
||||
@end
|
||||
+3
-2
@@ -150,8 +150,10 @@ CPWebViewScrollNative = 2;
|
||||
|
||||
|
||||
_frameView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||
[_frameView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
|
||||
_scrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
|
||||
[_scrollView setAutohidesScrollers:YES];
|
||||
[_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
[_scrollView setDocumentView:_frameView];
|
||||
|
||||
@@ -166,7 +168,6 @@ CPWebViewScrollNative = 2;
|
||||
- (void)setFrameSize:(CPSize)aSize
|
||||
{
|
||||
[super setFrameSize:aSize];
|
||||
|
||||
[self _resizeWebFrame];
|
||||
}
|
||||
|
||||
@@ -180,7 +181,7 @@ CPWebViewScrollNative = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
[_frameView setFrameSize:[_scrollView bounds].size];
|
||||
[_frameView setFrameSize:[_scrollView contentSize]];
|
||||
|
||||
// try to get the document size so we can correctly set the frame
|
||||
var win = null;
|
||||
|
||||
+586
-148
File diff suppressed because it is too large.
Load diff
@@ -38,6 +38,11 @@ var _CPToolbarViewBackgroundColor = nil;
|
||||
return _CPToolbarViewBackgroundColor;
|
||||
}
|
||||
|
||||
- (void)setShowsResizeIndicator:(BOOL)shouldShowResizeIndicator
|
||||
{
|
||||
// We don't ever want to show the resize indicator.
|
||||
}
|
||||
|
||||
- (void)tile
|
||||
{
|
||||
[super tile];
|
||||
@@ -66,11 +71,12 @@ var _CPToolbarViewBackgroundColor = nil;
|
||||
[self addSubview:_toolbarBackgroundView positioned:CPWindowBelow relativeTo:nil];
|
||||
}
|
||||
|
||||
var frame = CGRectMakeZero();
|
||||
|
||||
frame.origin = CGPointMakeCopy([self toolbarOffset]);
|
||||
var frame = CGRectMakeZero(),
|
||||
toolbarOffset = [self toolbarOffset];
|
||||
|
||||
frame.origin = CGPointMake(toolbarOffset.width, toolbarOffset.height);
|
||||
frame.size = [_toolbarView frame].size;
|
||||
|
||||
|
||||
[_toolbarBackgroundView setFrame:frame];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
@import "_CPWindowView.j"
|
||||
|
||||
var _CPStandardWindowViewBodyBackgroundColor = nil;
|
||||
|
||||
@implementation _CPDocModalWindowView : _CPWindowView
|
||||
{
|
||||
CPView _bodyView;
|
||||
}
|
||||
|
||||
+ (CPColor)bodyBackgroundColor
|
||||
{
|
||||
if (!_CPStandardWindowViewBodyBackgroundColor)
|
||||
_CPStandardWindowViewBodyBackgroundColor = [CPColor colorWithWhite:0.96 alpha:0.9];
|
||||
|
||||
return _CPStandardWindowViewBodyBackgroundColor;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
self = [super initWithFrame:aFrame styleMask:aStyleMask];
|
||||
|
||||
if (self)
|
||||
{
|
||||
var theClass = [self class],
|
||||
bounds = [self bounds];
|
||||
|
||||
_bodyView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), CGRectGetHeight(bounds))];
|
||||
|
||||
[_bodyView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
[_bodyView setBackgroundColor:[theClass bodyBackgroundColor]];
|
||||
[_bodyView setHitTests:NO];
|
||||
|
||||
[self addSubview:_bodyView];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
return aFrameRect;
|
||||
}
|
||||
|
||||
- (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
return aContentRect;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -48,7 +48,7 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(6.0, 78.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(6.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(1.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(5.0, 5.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(6.0, 1.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(6.0, 6.0)],
|
||||
|
||||
@@ -94,11 +94,15 @@ var _CPTexturedWindowHeadGradientColor = nil,
|
||||
|
||||
@end
|
||||
|
||||
var _CPStandardWindowViewBodyBackgroundColor = nil,
|
||||
_CPStandardWindowViewDividerBackgroundColor = nil,
|
||||
_CPStandardWindowViewTitleBackgroundColor = nil,
|
||||
_CPStandardWindowViewCloseButtonImage = nil,
|
||||
_CPStandardWindowViewCloseButtonHighlightedImage = nil;
|
||||
var _CPStandardWindowViewBodyBackgroundColor = nil,
|
||||
_CPStandardWindowViewDividerBackgroundColor = nil,
|
||||
_CPStandardWindowViewTitleBackgroundColor = nil,
|
||||
_CPStandardWindowViewCloseButtonImage = nil,
|
||||
_CPStandardWindowViewCloseButtonHighlightedImage = nil,
|
||||
_CPStandardWindowViewCloseButtonUnsavedImage = nil,
|
||||
_CPStandardWindowViewCloseButtonUnsavedHighlightedImage = nil,
|
||||
_CPStandardWindowViewMinimizeButtonImage = nil,
|
||||
_CPStandardWindowViewMinimizeButtonHighlightedImage = nil;
|
||||
|
||||
var STANDARD_GRADIENT_HEIGHT = 41.0;
|
||||
STANDARD_TITLEBAR_HEIGHT = 25.0;
|
||||
@@ -112,6 +116,9 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
|
||||
|
||||
CPTextField _titleField;
|
||||
CPButton _closeButton;
|
||||
CPButton _minimizeButton;
|
||||
|
||||
BOOL _isDocumentEdited;
|
||||
}
|
||||
|
||||
+ (CPColor)bodyBackgroundColor
|
||||
@@ -230,7 +237,7 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
|
||||
[_bodyView setHitTests:NO];
|
||||
|
||||
[self addSubview:_bodyView];
|
||||
|
||||
|
||||
[self setResizeIndicatorOffset:CGSizeMake(2.0, 2.0)];
|
||||
|
||||
_titleField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
@@ -256,24 +263,44 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
|
||||
if (!_CPStandardWindowViewCloseButtonImage)
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[CPWindow class]];
|
||||
|
||||
|
||||
_CPStandardWindowViewCloseButtonImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardCloseButton.png"] size:CGSizeMake(16.0, 16.0)];
|
||||
_CPStandardWindowViewCloseButtonHighlightedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardCloseButtonHighlighted.png"] size:CGSizeMake(16.0, 16.0)];
|
||||
_CPStandardWindowViewCloseButtonUnsavedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardCloseButtonUnsaved.png"] size:CGSizeMake(16.0, 16.0)];
|
||||
_CPStandardWindowViewCloseButtonUnsavedHighlightedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardCloseButtonUnsavedHighlighted.png"] size:CGSizeMake(16.0, 16.0)];
|
||||
}
|
||||
|
||||
|
||||
_closeButton = [[CPButton alloc] initWithFrame:CGRectMake(8.0, 7.0, 16.0, 16.0)];
|
||||
|
||||
|
||||
[_closeButton setBordered:NO];
|
||||
|
||||
[_closeButton setImage:_CPStandardWindowViewCloseButtonImage];
|
||||
[_closeButton setAlternateImage:_CPStandardWindowViewCloseButtonHighlightedImage];
|
||||
|
||||
[self _updateCloseButton];
|
||||
|
||||
[self addSubview:_closeButton];
|
||||
}
|
||||
|
||||
|
||||
if (_styleMask & CPMiniaturizableWindowMask && ![CPPlatform isBrowser])
|
||||
{
|
||||
if (!_CPStandardWindowViewMinimizeButtonImage)
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[CPWindow class]];
|
||||
|
||||
_CPStandardWindowViewMinimizeButtonImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardMinimizeButton.png"] size:CGSizeMake(16.0, 16.0)];
|
||||
_CPStandardWindowViewMinimizeButtonHighlightedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardMinimizeButtonHighlighted.png"] size:CGSizeMake(16.0, 16.0)];
|
||||
}
|
||||
|
||||
_minimizeButton = [[CPButton alloc] initWithFrame:CGRectMake(27.0, 7.0, 16.0, 16.0)];
|
||||
|
||||
[_minimizeButton setBordered:NO];
|
||||
|
||||
[_minimizeButton setImage:_CPStandardWindowViewMinimizeButtonImage];
|
||||
[_minimizeButton setAlternateImage:_CPStandardWindowViewMinimizeButtonHighlightedImage];
|
||||
|
||||
[self addSubview:_minimizeButton];
|
||||
}
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -281,6 +308,9 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
|
||||
{
|
||||
[_closeButton setTarget:[self window]];
|
||||
[_closeButton setAction:@selector(performClose:)];
|
||||
|
||||
[_minimizeButton setTarget:[self window]];
|
||||
[_minimizeButton setAction:@selector(performMiniaturize:)];
|
||||
}
|
||||
|
||||
- (CGSize)toolbarOffset
|
||||
@@ -303,7 +333,14 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
|
||||
|
||||
[_bodyView setFrame:CGRectMake(0.0, dividerMaxY, width, CGRectGetHeight(bounds) - dividerMaxY)];
|
||||
|
||||
[_titleField setFrame:CGRectMake(10.0, 3.0, width - 20.0, CGRectGetHeight([_titleField frame]))];
|
||||
var leftOffset = 8;
|
||||
|
||||
if (_closeButton)
|
||||
leftOffset += 19.0;
|
||||
if (_minimizeButton)
|
||||
leftOffset += 19.0;
|
||||
|
||||
[_titleField setFrame:CGRectMake(leftOffset, 5.0, width - leftOffset*2.0, CGRectGetHeight([_titleField frame]))];
|
||||
|
||||
[[theWindow contentView] setFrameOrigin:CGPointMake(0.0, CGRectGetMaxY([_dividerView frame]))];
|
||||
}
|
||||
@@ -334,6 +371,27 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
- (void)_updateCloseButton
|
||||
{
|
||||
if (_isDocumentEdited)
|
||||
{
|
||||
[_closeButton setImage:_CPStandardWindowViewCloseButtonUnsavedImage];
|
||||
[_closeButton setAlternateImage:_CPStandardWindowViewCloseButtonUnsavedHighlightedImage];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_closeButton setImage:_CPStandardWindowViewCloseButtonImage];
|
||||
[_closeButton setAlternateImage:_CPStandardWindowViewCloseButtonHighlightedImage];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setDocumentEdited:(BOOL)isEdited
|
||||
{
|
||||
_isDocumentEdited = isEdited;
|
||||
[self _updateCloseButton];
|
||||
}
|
||||
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
[_titleField setStringValue:aTitle];
|
||||
|
||||
@@ -36,7 +36,9 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
||||
CGSize _resizeIndicatorOffset;
|
||||
|
||||
CPView _toolbarView;
|
||||
CGSize _toolbarOffset;
|
||||
// BOOL _isAnimatingToolbar;
|
||||
|
||||
|
||||
CGRect _resizeFrame;
|
||||
CGPoint _mouseDraggedPoint;
|
||||
@@ -79,15 +81,17 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
||||
if (self)
|
||||
{
|
||||
_styleMask = aStyleMask;
|
||||
_resizeIndicatorOffset = CGSizeMake(0.0, 0.0);
|
||||
_toolbarOffset = CGSizeMake(0.0, 0.0);
|
||||
|
||||
[self setShowsResizeIndicator:!(_styleMask & CPBorderlessBridgeWindowMask) && (_styleMask & CPResizableWindowMask)];
|
||||
_resizeIndicatorOffset = CGSizeMakeZero();
|
||||
_toolbarOffset = CGSizeMakeZero();
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setDocumentEdited:(BOOL)isEdited
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
}
|
||||
@@ -135,7 +139,14 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
||||
}
|
||||
|
||||
else if (type === CPLeftMouseDragged)
|
||||
[theWindow setFrameSize:CGSizeMake(CGRectGetWidth(_resizeFrame) + location.x - CGRectGetMinX(_resizeFrame), CGRectGetHeight(_resizeFrame) + location.y - CGRectGetMinY(_resizeFrame))];
|
||||
{
|
||||
var newSize = CGSizeMake(CGRectGetWidth(_resizeFrame) + location.x - CGRectGetMinX(_resizeFrame), CGRectGetHeight(_resizeFrame) + location.y - CGRectGetMinY(_resizeFrame));
|
||||
|
||||
if (theWindow._isSheet && theWindow._parentView && (theWindow._frame.size.width !== newSize.width))
|
||||
[theWindow._parentView _setAttachedSheetFrameOrigin];
|
||||
|
||||
[theWindow setFrameSize:newSize];
|
||||
}
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
@@ -151,10 +162,15 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
||||
if (!visibleFrame)
|
||||
visibleFrame = [[CPPlatformWindow primaryPlatformWindow] visibleFrame];
|
||||
|
||||
var minPointY = 0;
|
||||
|
||||
if([CPMenu menuBarVisible])
|
||||
minPointY = [[CPApp mainMenu] menuBarHeight];
|
||||
|
||||
var restrictedPoint = CGPointMake(0, 0);
|
||||
|
||||
restrictedPoint.x = MIN(MAX(aPoint.x, -_frame.size.width + 4.0), CGRectGetMaxX(visibleFrame) - 4.0);
|
||||
restrictedPoint.y = MIN(MAX(aPoint.y, 0.0), CGRectGetMaxY(visibleFrame) - 8.0);
|
||||
restrictedPoint.y = MIN(MAX(aPoint.y, minPointY), CGRectGetMaxY(visibleFrame) - 8.0);
|
||||
|
||||
return restrictedPoint;
|
||||
}
|
||||
@@ -202,18 +218,18 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
||||
|
||||
[_resizeIndicator setImage:_CPWindowViewResizeIndicatorImage];
|
||||
[_resizeIndicator setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
|
||||
|
||||
|
||||
[self addSubview:_resizeIndicator];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_resizeIndicator removeFromSuperview];
|
||||
|
||||
|
||||
_resizeIndicator = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (CPImage)showsResizeIndicator
|
||||
- (BOOL)showsResizeIndicator
|
||||
{
|
||||
return _resizeIndicator !== nil;
|
||||
}
|
||||
@@ -254,7 +270,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
||||
|
||||
- (CGSize)toolbarOffset
|
||||
{
|
||||
return CGSizeMakeZero();
|
||||
return _toolbarOffset;
|
||||
}
|
||||
|
||||
- (CPColor)toolbarLabelColor
|
||||
@@ -311,11 +327,8 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
||||
if (toolbarView)
|
||||
{
|
||||
[toolbarView removeFromSuperview];
|
||||
[toolbarView setLabelColor:[self toolbarLabelColor]];
|
||||
|
||||
if ([self respondsToSelector:@selector(toolbarLabelShadowColor)])
|
||||
[toolbarView setLabelShadowColor:[self toolbarLabelShadowColor]];
|
||||
|
||||
[toolbarView FIXME_setIsHUD:_styleMask & CPHUDBackgroundWindowMask];
|
||||
|
||||
[self addSubview:toolbarView];
|
||||
}
|
||||
|
||||
|
||||
+53
-13
@@ -43,8 +43,10 @@
|
||||
{
|
||||
CPWindow _window;
|
||||
|
||||
CPArray _documents;
|
||||
CPDocument _document;
|
||||
BOOL _shouldCloseDocument;
|
||||
BOOL _supportsMultipleDocuments;
|
||||
|
||||
id _cibOwner;
|
||||
CPString _windowCibName;
|
||||
@@ -74,6 +76,8 @@
|
||||
[self setShouldCloseDocument:NO];
|
||||
|
||||
[self setNextResponder:CPApp];
|
||||
|
||||
_documents = [];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -140,7 +144,7 @@
|
||||
{
|
||||
var theWindow = [self window];
|
||||
|
||||
if ([theWindow respondsToSelector:@selector(becomesKeyOnlyIfNeeded)] && [theWindow becomesKeyOnlyIfNeeded])
|
||||
if ([theWindow respondsToSelector:@selector(becomesKeyOnlyIfNeeded)] && [theWindow becomesKeyOnlyIfNeeded])
|
||||
[theWindow orderFront:aSender];
|
||||
else
|
||||
[theWindow makeKeyAndOrderFront:aSender];
|
||||
@@ -169,6 +173,14 @@
|
||||
|
||||
if (_window === nil && [_cibOwner isKindOfClass:[CPDocument class]])
|
||||
[self setWindow:[_cibOwner valueForKey:@"window"]];
|
||||
|
||||
if (!_window)
|
||||
{
|
||||
var reason = [CPString stringWithFormat:@"Window for %@ could not be loaded from Cib or no window specified. \
|
||||
Override loadWindow to load the window manually.", self];
|
||||
|
||||
[CPException raise:CPInternalInconsistencyException reason:reason];
|
||||
}
|
||||
|
||||
[self windowDidLoad];
|
||||
[_document windowControllerDidLoadCib:self];
|
||||
@@ -220,6 +232,9 @@
|
||||
|
||||
if (_document)
|
||||
{
|
||||
if (![self supportsMultipleDocuments])
|
||||
[self removeDocument:_document];
|
||||
|
||||
[defaultCenter removeObserver:self
|
||||
name:CPDocumentWillSaveNotification
|
||||
object:_document];
|
||||
@@ -237,6 +252,8 @@
|
||||
|
||||
if (_document)
|
||||
{
|
||||
[self addDocument:_document];
|
||||
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(_documentWillSave:)
|
||||
name:CPDocumentWillSaveNotification
|
||||
@@ -263,23 +280,46 @@
|
||||
[self synchronizeWindowTitleWithDocumentName];
|
||||
}
|
||||
|
||||
- (void)setViewController:(CPViewController)aViewController
|
||||
- (void)setSupportsMultipleDocuments:(BOOL)shouldSupportMultipleDocuments
|
||||
{
|
||||
var containerView = [self viewControllerContainerView] || [[self window] contentView],
|
||||
view = [_viewController view],
|
||||
frame = view ? [view frame] : [containerView bounds];
|
||||
_supportsMultipleDocuments = shouldSupportMultipleDocuments;
|
||||
}
|
||||
|
||||
[view removeFromSuperview];
|
||||
- (BOOL)supportsMultipleDocuments
|
||||
{
|
||||
return _supportsMultipleDocuments;
|
||||
}
|
||||
|
||||
_viewController = aViewController;
|
||||
- (void)addDocument:(CPDocument)aDocument
|
||||
{
|
||||
if (aDocument && ![_documents containsObject:aDocument])
|
||||
[_documents addObject:aDocument];
|
||||
}
|
||||
|
||||
view = [_viewController view];
|
||||
- (void)removeDocument:(CPDocument)aDocument
|
||||
{
|
||||
var index = [_documents indexOfObjectIdenticalTo:aDocument];
|
||||
|
||||
if (view)
|
||||
{
|
||||
[view setFrame:frame];
|
||||
[containerView addSubview:view];
|
||||
}
|
||||
if (index === CPNotFound)
|
||||
return;
|
||||
|
||||
[_documents removeObjectAtIndex:index];
|
||||
|
||||
if (_document === aDocument && [_documents count])
|
||||
[self setDocument:[_documents objectAtIndex:MIN(index, [_documents count] - 1)]];
|
||||
}
|
||||
|
||||
- (void)removeDocumentAndCloseIfNecessary:(CPDocument)aDocument
|
||||
{
|
||||
[self removeDocument:aDocument];
|
||||
|
||||
if (![_documents count])
|
||||
[self close];
|
||||
}
|
||||
|
||||
- (CPArray)documents
|
||||
{
|
||||
return _documents;
|
||||
}
|
||||
|
||||
- (void)setViewControllerContainerView:(CPView)aView
|
||||
|
||||
+8
-3
@@ -60,7 +60,7 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
|
||||
|
||||
if (self)
|
||||
{
|
||||
_data = [CPURLConnection sendSynchronousRequest:[CPURLRequest requestWithURL:aURL] returningResponse:nil error:nil];
|
||||
_data = [CPURLConnection sendSynchronousRequest:[CPURLRequest requestWithURL:aURL] returningResponse:nil];
|
||||
_awakenCustomResources = YES;
|
||||
}
|
||||
|
||||
@@ -171,12 +171,17 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
|
||||
|
||||
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)data
|
||||
{
|
||||
_data = [CPData dataWithString:data];
|
||||
// FIXME: Why aren't we getting connection:didFailWithError:
|
||||
if (!data)
|
||||
return [self connection:aConnection didFailWithError:nil];
|
||||
|
||||
_data = [CPData dataWithRawString:data];
|
||||
}
|
||||
|
||||
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
|
||||
{
|
||||
alert("cib: connection failed.");
|
||||
if ([_loadDelegate respondsToSelector:@selector(cibDidFailToLoad:)])
|
||||
[_loadDelegate cibDidFailToLoad:self];
|
||||
|
||||
_loadDelegate = nil;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
var selectorName = _label,
|
||||
selectorNameLength = [selectorName length];
|
||||
|
||||
if (selectorNameLength && selectorName[selectorNameLength - 1] !== ':')
|
||||
if (selectorNameLength && selectorName.charAt(selectorNameLength - 1) !== ':')
|
||||
selectorName += ':';
|
||||
|
||||
var selector = CPSelectorFromString(selectorName);
|
||||
|
||||
+44
-19
@@ -27,8 +27,6 @@
|
||||
|
||||
var CPCibOwner = @"CPCibOwner";
|
||||
|
||||
var LoadInfoForCib = {};
|
||||
|
||||
@implementation CPObject (CPCibLoading)
|
||||
|
||||
- (void)awakeFromCib
|
||||
@@ -63,9 +61,11 @@ var LoadInfoForCib = {};
|
||||
|
||||
+ (void)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable loadDelegate:aDelegate
|
||||
{
|
||||
var cib = [[CPCib alloc] initWithContentsOfURL:anAbsolutePath loadDelegate:self];
|
||||
|
||||
LoadInfoForCib[[cib UID]] = { loadDelegate:aDelegate, externalNameTable:aNameTable };
|
||||
[[CPCib alloc]
|
||||
initWithContentsOfURL:anAbsolutePath
|
||||
loadDelegate:[[_CPCibLoadDelegate alloc]
|
||||
initWithLoadDelegate:aDelegate
|
||||
externalNameTable:aNameTable]];
|
||||
}
|
||||
|
||||
+ (void)loadCibNamed:(CPString)aName owner:(id)anOwner loadDelegate:(id)aDelegate
|
||||
@@ -82,20 +82,45 @@ var LoadInfoForCib = {};
|
||||
|
||||
- (void)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable loadDelegate:(id)aDelegate
|
||||
{
|
||||
var cib = [[CPCib alloc] initWithCibNamed:aFileName bundle:self loadDelegate:[self class]];
|
||||
|
||||
LoadInfoForCib[[cib UID]] = { loadDelegate:aDelegate, externalNameTable:aNameTable };
|
||||
}
|
||||
|
||||
+ (void)cibDidFinishLoading:(CPCib)aCib
|
||||
{
|
||||
var loadInfo = LoadInfoForCib[[aCib UID]];
|
||||
|
||||
delete LoadInfoForCib[[aCib UID]];
|
||||
|
||||
[aCib instantiateCibWithExternalNameTable:loadInfo.externalNameTable];
|
||||
|
||||
[loadInfo.loadDelegate cibDidFinishLoading:aCib];
|
||||
[[CPCib alloc]
|
||||
initWithCibNamed:aFileName
|
||||
bundle:self
|
||||
loadDelegate:[[_CPCibLoadDelegate alloc]
|
||||
initWithLoadDelegate:aDelegate
|
||||
externalNameTable:aNameTable]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPCibLoadDelegate : CPObject
|
||||
{
|
||||
id _loadDelegate;
|
||||
CPDictionary _externalNameTable;
|
||||
}
|
||||
|
||||
- (id)initWithLoadDelegate:(id)aLoadDelegate externalNameTable:(id)anExternalNameTable
|
||||
{
|
||||
self = [self init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_loadDelegate = aLoadDelegate;
|
||||
_externalNameTable = anExternalNameTable;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)cibDidFinishLoading:(CPCib)aCib
|
||||
{
|
||||
[aCib instantiateCibWithExternalNameTable:_externalNameTable];
|
||||
|
||||
[_loadDelegate cibDidFinishLoading:aCib];
|
||||
}
|
||||
|
||||
- (void)cibDidFailToLoad:(CPCib)aCib
|
||||
{
|
||||
[_loadDelegate cibDidFailToLoad:aCib];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -83,7 +83,7 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
||||
if ([aCoder respondsToSelector:@selector(bundle)] &&
|
||||
(![aCoder respondsToSelector:@selector(awakenCustomResources)] || [aCoder awakenCustomResources]))
|
||||
if (_className === @"CPImage")
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:[_properties objectForKey:@"size"]];
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:_properties.valueForKey(@"size")];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,13 @@
|
||||
|
||||
- (void)setCustomClassName:(CPString)aClassName
|
||||
{
|
||||
if (_className === aClassName)
|
||||
return;
|
||||
|
||||
_className = aClassName;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -97,9 +103,7 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
|
||||
[view setBounds:[self bounds]];
|
||||
|
||||
// Since the object replacement logic hasn't had a chance to kick in yet, we need to do it manually:
|
||||
|
||||
// we need to copy subviews since each time we add a subview to a different view its removed from the original subviews array
|
||||
var subviews = [[self subviews] copy],
|
||||
var subviews = [self subviews],
|
||||
index = 0,
|
||||
count = subviews.length;
|
||||
|
||||
|
||||
@@ -2,18 +2,19 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
|
||||
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
|
||||
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
|
||||
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
|
||||
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
|
||||
|
||||
_CPCibWindowTemplateViewClassKey = @"_CPCibWindowTemplateViewClassKey",
|
||||
_CPCibWindowTemplateWindowClassKey = @"_CPCibWindowTemplateWindowClassKey",
|
||||
_CPCibWindowTemplateViewClassKey = @"_CPCibWindowTemplateViewClassKey",
|
||||
_CPCibWindowTemplateWindowClassKey = @"_CPCibWindowTemplateWindowClassKey",
|
||||
|
||||
_CPCibWindowTemplateWindowRectKey = @"_CPCibWindowTemplateWindowRectKey",
|
||||
_CPCibWindowTemplateWindowStyleMaskKey = @"_CPCibWindowTempatStyleMaskKey",
|
||||
_CPCibWindowTemplateWindowTitleKey = @"_CPCibWindowTemplateWindowTitleKey",
|
||||
_CPCibWindowTemplateWindowViewKey = @"_CPCibWindowTemplateWindowViewKey",
|
||||
_CPCibWindowTemplateWindowRectKey = @"_CPCibWindowTemplateWindowRectKey",
|
||||
_CPCibWindowTemplateWindowStyleMaskKey = @"_CPCibWindowTempatStyleMaskKey",
|
||||
_CPCibWindowTemplateWindowTitleKey = @"_CPCibWindowTemplateWindowTitleKey",
|
||||
_CPCibWindowTemplateWindowViewKey = @"_CPCibWindowTemplateWindowViewKey",
|
||||
|
||||
_CPCibWindowTemplateWindowIsFullBridgeKey = @"_CPCibWindowTemplateWindowIsFullBridgeKey";
|
||||
_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop = @"_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop";
|
||||
_CPCibWindowTemplateWindowIsFullPlatformWindowKey = @"_CPCibWindowTemplateWindowIsFullPlatformWindowKey";
|
||||
|
||||
@implementation _CPCibWindowTemplate : CPObject
|
||||
{
|
||||
@@ -30,7 +31,8 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeK
|
||||
CPString _windowTitle;
|
||||
CPView _windowView;
|
||||
|
||||
BOOL _windowIsFullBridge;
|
||||
BOOL _windowAutorecalculatesKeyViewLoop;
|
||||
BOOL _windowIsFullPlatformWindow;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
@@ -46,7 +48,7 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeK
|
||||
_windowTitle = @"Window";
|
||||
_windowView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 400.0, 200.0)];
|
||||
|
||||
_windowIsFullBridge = NO;
|
||||
_windowIsFullPlatformWindow = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -72,7 +74,8 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeK
|
||||
_windowTitle = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowTitleKey];
|
||||
_windowView = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowViewKey];
|
||||
|
||||
_windowIsFullBridge = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowIsFullBridgeKey];
|
||||
_windowAutorecalculatesKeyViewLoop = !![aCoder decodeObjectForKey:_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop];
|
||||
_windowIsFullPlatformWindow = !![aCoder decodeObjectForKey:_CPCibWindowTemplateWindowIsFullPlatformWindowKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -94,7 +97,11 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeK
|
||||
[aCoder encodeObject:_windowTitle forKey:_CPCibWindowTemplateWindowTitleKey];
|
||||
[aCoder encodeObject:_windowView forKey:_CPCibWindowTemplateWindowViewKey];
|
||||
|
||||
[aCoder encodeObject:_windowIsFullBridge forKey:_CPCibWindowTemplateWindowIsFullBridgeKey];
|
||||
if (_windowAutorecalculatesKeyViewLoop)
|
||||
[aCoder encodeObject:_windowAutorecalculatesKeyViewLoop forKey:_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop];
|
||||
|
||||
if (_windowIsFullPlatformWindow)
|
||||
[aCoder encodeObject:_windowIsFullPlatformWindow forKey:_CPCibWindowTemplateWindowIsFullPlatformWindowKey];
|
||||
}
|
||||
|
||||
- (CPString)customClassName
|
||||
@@ -127,9 +134,8 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeK
|
||||
[theWindow setMinSize:_minSize];
|
||||
if (_maxSize)
|
||||
[theWindow setMaxSize:_maxSize];
|
||||
[theWindow setLevel:CPFloatingWindowLevel];
|
||||
|
||||
//[result setHidesOnDeactivate:(_wtFlags&0x80000000)?YES:NO];
|
||||
//[result setHidesOnDeactivate:(_wtFlags&0x80000000)?YES:NO];
|
||||
[theWindow setTitle:_windowTitle];
|
||||
|
||||
// FIXME: we can't autoresize yet...
|
||||
@@ -144,7 +150,8 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeK
|
||||
[theWindow setToolbar:_viewClass];
|
||||
}
|
||||
|
||||
[theWindow setFullBridge:_windowIsFullBridge];
|
||||
[theWindow setAutorecalculatesKeyViewLoop:_windowAutorecalculatesKeyViewLoop];
|
||||
[theWindow setFullBridge:_windowIsFullPlatformWindow];
|
||||
|
||||
return theWindow;
|
||||
}
|
||||
|
||||
@@ -777,8 +777,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
|
||||
@ignore
|
||||
*/
|
||||
+ (void)runLoopUpdateLayers
|
||||
{if (window.oops) {alert(window.latest); objj_debug_print_backtrace();}
|
||||
window.loop = true;
|
||||
{
|
||||
for (UID in CALayerRegisteredRunLoopUpdates)
|
||||
{
|
||||
var layer = CALayerRegisteredRunLoopUpdates[UID],
|
||||
|
||||
@@ -312,7 +312,6 @@ function CGContextDrawLinearGradient(aContext, aGradient, aStartPoint, anEndPoin
|
||||
}
|
||||
|
||||
aContext.gState.gradient = vml.join("");
|
||||
console.log(vml.join(""));
|
||||
|
||||
// if (aContext.buffer != nil)
|
||||
// aContext.buffer += vml.join("");
|
||||
|
||||
@@ -70,6 +70,8 @@ _function(CGInsetMakeZero())
|
||||
_function(CGInsetMakeCopy(anInset))
|
||||
_function(CGInsetIsEmpty(anInset))
|
||||
|
||||
CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 0.0);
|
||||
|
||||
/*!
|
||||
@addtogroup appkit
|
||||
@{
|
||||
@@ -174,6 +176,15 @@ function CGRectStandardize(aRect)
|
||||
|
||||
function CGRectUnion(lhsRect, rhsRect)
|
||||
{
|
||||
var lhsRectIsNull = !lhsRect || lhsRect === CGRectNull,
|
||||
rhsRectIsNull = !rhsRect || rhsRect === CGRectNull;
|
||||
|
||||
if (lhsRectIsNull)
|
||||
return rhsRectIsNull ? CGRectNull : rhsRect;
|
||||
|
||||
if (rhsRectIsNull)
|
||||
return lhsRectIsNull ? CGRectNull : lhsRect;
|
||||
|
||||
var minX = MIN(_CGRectGetMinX(lhsRect), _CGRectGetMinX(rhsRect)),
|
||||
minY = MIN(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)),
|
||||
maxX = MAX(_CGRectGetMaxX(lhsRect), _CGRectGetMaxX(rhsRect)),
|
||||
|
||||
@@ -210,7 +210,7 @@ function CGPathAddQuadCurveToPoint(aPath, aTransform, cpx, cpy, x, y)
|
||||
|
||||
if (aTransform)
|
||||
{
|
||||
cp = _CGPointApplyAffineTransform(control, aTransform);
|
||||
cp = _CGPointApplyAffineTransform(cp, aTransform);
|
||||
end = _CGPointApplyAffineTransform(end, aTransform);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
<dict>
|
||||
<key>CPBundleIdentifier</key>
|
||||
<string>com.280n.AppKit</string>
|
||||
<key>Default Themes Path</key>
|
||||
<string>Default.cptheme</string>
|
||||
<key>Default Theme Name</key>
|
||||
<string>Default</string>
|
||||
<key>CPBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CPBundleName</key>
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
require("../common.jake");
|
||||
|
||||
var framework = require("objective-j/jake").framework;
|
||||
var BundleTask = require("objective-j/jake").BundleTask;
|
||||
|
||||
$BUILD_PATH = FILE.join($BUILD_DIR, $CONFIGURATION, 'AppKit');
|
||||
|
||||
AppKitFiles = new FileList("**/*.j").exclude('CoreGraphics/CGContextCanvas.j', 'CoreGraphics/CGContextVML.j', 'Themes/**/*', 'Tools/**/*', "Platform/DOM/CPPlatform.j", "Platform/DOM/CPPlatformString.j");
|
||||
|
||||
FIXME_fileDependency (FILE.join("Platform", "CPPlatform.j"), FILE.join("Platform", "DOM", "CPPlatform.j"));
|
||||
FIXME_fileDependency (FILE.join("Platform", "CPPlatformString.j"), FILE.join("Platform", "DOM", "CPPlatformString.j"));
|
||||
|
||||
appKitTask = framework ("AppKit", function(appKitTask)
|
||||
{
|
||||
appKitTask.setBuildIntermediatesPath(FILE.join($BUILD_DIR, "AppKit.build", $CONFIGURATION))
|
||||
appKitTask.setBuildPath($BUILD_CONFIGURATION_DIR);
|
||||
|
||||
appKitTask.setAuthor("280 North, Inc.");
|
||||
appKitTask.setEmail("feedback @nospam@ 280north.com");
|
||||
appKitTask.setSummary("AppKit classes for Cappuccino");
|
||||
appKitTask.setIdentifier("com.280n.AppKit");
|
||||
appKitTask.setVersion(getCappuccinoVersion());
|
||||
appKitTask.setLicense(BundleTask.License.LGPL_v2_1);
|
||||
appKitTask.setSources(AppKitFiles);
|
||||
appKitTask.setResources(new FileList("Resources/**/*"));
|
||||
appKitTask.setFlattensSources(true);
|
||||
appKitTask.setInfoPlistPath("Info.plist");
|
||||
|
||||
if ($CONFIGURATION === "Release")
|
||||
appKitTask.setCompilerFlags("-O");
|
||||
else
|
||||
appKitTask.setCompilerFlags("-DDEBUG -g");
|
||||
});
|
||||
|
||||
$BUILD_CJS_CAPPUCCINO_APPKIT = FILE.join($BUILD_CJS_CAPPUCCINO_FRAMEWORKS, "AppKit");
|
||||
|
||||
filedir ($BUILD_CJS_CAPPUCCINO_APPKIT, ["AppKit"], function()
|
||||
{
|
||||
cp_r(appKitTask.buildProductPath(), $BUILD_CJS_CAPPUCCINO_APPKIT);
|
||||
});
|
||||
|
||||
subtasks (["Themes"], ["clean", "clobber"]);
|
||||
|
||||
task ("Theme", [$BUILD_CJS_CAPPUCCINO_APPKIT], function()
|
||||
{
|
||||
subjake(["Themes"], "build");
|
||||
|
||||
cp_r(FILE.join($BUILD_DIR, $CONFIGURATION, 'Aristo.blend'), FILE.join($BUILD_PATH, 'Resources', 'Aristo.blend'));
|
||||
cp_r(FILE.join($BUILD_DIR, $CONFIGURATION, 'Aristo.blend'), FILE.join($BUILD_CJS_CAPPUCCINO_APPKIT, "Resources", "Aristo.blend"));
|
||||
});
|
||||
|
||||
task ("build", ["AppKit", $BUILD_CJS_CAPPUCCINO_APPKIT, "Theme"]);
|
||||
|
||||
CLOBBER.include($BUILD_CJS_CAPPUCCINO_APPKIT);
|
||||
@@ -1,471 +0,0 @@
|
||||
/*
|
||||
* CPTableColumn.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2008, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/Foundation.j>
|
||||
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
|
||||
/*
|
||||
@global
|
||||
@class CPTableColumn
|
||||
*/
|
||||
CPTableColumnNoResizing = 0;
|
||||
/*
|
||||
@global
|
||||
@class CPTableColumn
|
||||
*/
|
||||
CPTableColumnAutoresizingMask = 1;
|
||||
/*
|
||||
@global
|
||||
@class CPTableColumn
|
||||
*/
|
||||
CPTableColumnUserResizingMask = 2;
|
||||
|
||||
#define PurgableInfoMake(aView, aRow) { view:(aView), row:(aRow) }
|
||||
#define PurgableInfoView(anInfo) ((anInfo).view)
|
||||
#define PurgableInfoRow(anInfo) ((anInfo).row)
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPTableColumn
|
||||
|
||||
An CPTableColumn object mainly keeps information about the width of the column, its minimum and maximum width; whether the column can be edited or resized; and the cells used to draw the column header and the data in the column. You can change all these attributes of the column by calling the appropriate methods. Please note that the table column does not hold nor has access to the data to be displayed in the column; this data is maintained in the table view's data source.</p>
|
||||
|
||||
<p>Each CPTableColumn object is identified by a CPString, called the column identifier. The reason is that, after a column has been added to a table view, the user might move the columns around, so there is a need to identify the columns regardless of its position in the table.
|
||||
|
||||
@ignore
|
||||
*/
|
||||
@implementation CPTableColumn : CPObject
|
||||
{
|
||||
CPString _identifier;
|
||||
CPView _headerView;
|
||||
|
||||
CPTableView _tableView;
|
||||
|
||||
float _width;
|
||||
float _minWidth;
|
||||
float _maxWidth;
|
||||
|
||||
unsigned _resizingMask;
|
||||
|
||||
CPView _dataView; // default data view for this column
|
||||
|
||||
Object _dataViewData; // cache of data view archives (key=data view UID, value=data view archive)
|
||||
Object _dataViewForView; // mapping from view instances back to their data view prototype (key=view instance UID, value=data view)
|
||||
Object _purgableInfosForDataView; // (key=data view UID, value=)
|
||||
}
|
||||
|
||||
/*!
|
||||
Initializes the table column with the specified identifier.
|
||||
@param anIdentifier the identifier
|
||||
@return the initialized table column
|
||||
*/
|
||||
- (id)initWithIdentifier:(CPString)anIdentifier
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self _init];
|
||||
|
||||
_identifier = anIdentifier;
|
||||
|
||||
_width = 40.0;
|
||||
_minWidth = 8.0;
|
||||
_maxWidth = 1000.0;
|
||||
|
||||
var dataView = [[CPTextField alloc] initWithFrame:CPRectMakeZero()];
|
||||
[dataView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateHighlighted];
|
||||
|
||||
[self setDataView:dataView];
|
||||
|
||||
_headerView = [[CPTextField alloc] initWithFrame:CPRectMakeZero()];
|
||||
[_headerView setBackgroundColor:[CPColor greenColor]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_dataViewData = {};
|
||||
_dataViewForView = {};
|
||||
_purgableInfosForDataView = {};
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the table column's identifier
|
||||
@param anIdentifier the new identifier
|
||||
*/
|
||||
- (void)setIdentifier:(CPString)anIdentifier
|
||||
{
|
||||
_identifier = anIdentifier;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the table column's identifier
|
||||
*/
|
||||
- (CPString)identifier
|
||||
{
|
||||
return _identifier;
|
||||
}
|
||||
|
||||
// Setting the CPTableView
|
||||
/*!
|
||||
Sets the table's view. This is called automatically by Cappuccino.
|
||||
@param aTableView the new table view
|
||||
*/
|
||||
- (void)setTableView:(CPTableView)aTableView
|
||||
{
|
||||
_tableView = aTableView;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the column's table view.
|
||||
*/
|
||||
- (CPTableView)tableView
|
||||
{
|
||||
return _tableView;
|
||||
}
|
||||
|
||||
// Controlling size
|
||||
/*!
|
||||
Sets the column's width.
|
||||
@param aWidth the new column width
|
||||
*/
|
||||
- (void)setWidth:(float)aWidth
|
||||
{
|
||||
_width = aWidth;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the column's width
|
||||
*/
|
||||
- (float)width
|
||||
{
|
||||
return _width;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets column's minimum width.
|
||||
@param aWidth the new minimum column width
|
||||
*/
|
||||
- (void)setMinWidth:(float)aWidth
|
||||
{
|
||||
if (_width < (_minWidth = aWidth))
|
||||
[self setWidth:_minWidth];
|
||||
}
|
||||
|
||||
/*!
|
||||
The column's minimum width
|
||||
*/
|
||||
- (float)minWidth
|
||||
{
|
||||
return _minWidth;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the column's maximum width.
|
||||
@param aWidth the new maximum width
|
||||
*/
|
||||
- (void)setMaxWidth:(float)aWidth
|
||||
{
|
||||
if (_width > (_maxmimumWidth = aWidth))
|
||||
[self setWidth:_maxWidth];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the resizing mask. The mask is one of:
|
||||
<pre>
|
||||
CPTableColumnNoResizing;
|
||||
CPTableColumnAutoresizingMask;
|
||||
CPTableColumnUserResizingMask;
|
||||
</pre>
|
||||
@param aMask the new resizing mask
|
||||
*/
|
||||
- (void)setResizingMask:(unsigned)aMask
|
||||
{
|
||||
_resizingMask = aMask;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the column's resizing mask. One of:
|
||||
<pre>
|
||||
CPTableColumnNoResizing;
|
||||
CPTableColumnAutoresizingMask;
|
||||
CPTableColumnUserResizingMask;
|
||||
</pre>
|
||||
*/
|
||||
- (unsigned)resizingMask
|
||||
{
|
||||
return _resizingMask;
|
||||
}
|
||||
|
||||
/*!
|
||||
Resizes the column according to the min, max and set width.
|
||||
*/
|
||||
- (void)sizeToFit
|
||||
{
|
||||
var width = CPRectGetWidth([_headerView frame]);
|
||||
|
||||
if (width < _minWidth)
|
||||
[self setMinWidth:width];
|
||||
else if (width > _maxWidth)
|
||||
[self setMaxWidth:width]
|
||||
|
||||
if (_width != width)
|
||||
[self setWidth:width];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether the column in this data is editable.
|
||||
@param aFlag <code>YES</code> means the column data is editable
|
||||
*/
|
||||
- (void)setEditable:(BOOL)aFlag
|
||||
{
|
||||
_isEditable = aFlag;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns <code>YES</code> if the column data is editable.
|
||||
*/
|
||||
- (BOOL)isEditable
|
||||
{
|
||||
return _isEditable;
|
||||
}
|
||||
|
||||
//Setting the column header view
|
||||
|
||||
/*!
|
||||
Sets the view that draws the column's header.
|
||||
@param aHeaderView the view that will draws the column header
|
||||
*/
|
||||
|
||||
- (void)setHeaderView:(CPView)aView
|
||||
{
|
||||
_headerView = aView;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the view that draws the column's header
|
||||
*/
|
||||
- (CPView)headerView
|
||||
{
|
||||
return _headerView;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the data cell that draws rows in this column.
|
||||
*/
|
||||
- (void)setDataCell:(CPView <CPCoding>)aView
|
||||
{
|
||||
[self setDataView:aView];
|
||||
}
|
||||
|
||||
/*
|
||||
Sets the data view that draws rows in this column.
|
||||
*/
|
||||
- (void)setDataView:(CPView <CPCoding>)aView
|
||||
{
|
||||
if (_dataView)
|
||||
_dataViewData[[_dataView UID]] = nil;
|
||||
|
||||
_dataView = aView;
|
||||
_dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the data cell that draws rows in this column
|
||||
*/
|
||||
- (CPCell)dataCell
|
||||
{
|
||||
return _dataView;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the data view that draws rows in this column
|
||||
*/
|
||||
- (CPView)dataView
|
||||
{
|
||||
return [self dataCell];
|
||||
}
|
||||
|
||||
/*!
|
||||
By default returns the value from <code>dataCell</code>. This can
|
||||
be overridden by a subclass to return different cells for different
|
||||
rows.
|
||||
@param aRowIndex the index of the row to obtain the cell for
|
||||
*/
|
||||
- (CPCell)dataCellForRow:(int)aRowIndex
|
||||
{
|
||||
return [self dataView];
|
||||
}
|
||||
|
||||
- (CPView)dataViewForRow:(int)aRowIndex
|
||||
{
|
||||
return [self dataCellForRow:aRowIndex];
|
||||
}
|
||||
/*
|
||||
- (void)_markViewAsPurgable:(CPView)aView
|
||||
{
|
||||
var viewUID = [aView UID],
|
||||
dataViewUID = [_dataViewForView[viewUID] UID];
|
||||
|
||||
if (!_purgableInfosForDataView[dataViewUID])
|
||||
_purgableInfosForDataView[dataViewUID] = [CPDictionary dictionary];
|
||||
|
||||
[_purgableInfosForDataView[dataViewUID] setObject:aView forKey:viewUID];
|
||||
}
|
||||
*/
|
||||
- (void)_markView:(CPView)aView inRow:(unsigned)aRow asPurgable:(BOOL)isPurgable
|
||||
{
|
||||
var viewUID = [aView UID],
|
||||
dataViewUID = [_dataViewForView[viewUID] UID];
|
||||
|
||||
if (!_purgableInfosForDataView[dataViewUID])
|
||||
{
|
||||
if (!isPurgable)
|
||||
return;
|
||||
|
||||
_purgableInfosForDataView[dataViewUID] = {};
|
||||
}
|
||||
|
||||
if (!isPurgable) {
|
||||
if (_purgableInfosForDataView[dataViewUID][viewUID])
|
||||
CPLog.warn("removing unpurgable " + _purgableInfosForDataView[dataViewUID][viewUID]);
|
||||
delete _purgableInfosForDataView[dataViewUID][viewUID];
|
||||
}
|
||||
else
|
||||
_purgableInfosForDataView[dataViewUID][viewUID] = PurgableInfoMake(aView, aRow);
|
||||
}
|
||||
|
||||
- (CPView)_newDataViewForRow:(int)aRowIndex avoidingRows:(CPRange)rows
|
||||
{
|
||||
var view = [self dataViewForRow:aRowIndex],
|
||||
viewUID = [view UID],
|
||||
purgableInfos = _purgableInfosForDataView[viewUID];
|
||||
|
||||
if (purgableInfos)
|
||||
{
|
||||
for (var key in purgableInfos)
|
||||
{
|
||||
var info = purgableInfos[key];
|
||||
//if (!CPLocationInRange(PurgableInfoRow(info), rows))
|
||||
//{
|
||||
//CPLog.debug("yes, a purged view is usable, its called: " + PurgableInfoView(info));
|
||||
delete purgableInfos[key];
|
||||
return PurgableInfoView(info);
|
||||
//}
|
||||
//else
|
||||
// CPLog.warn("avoiding");
|
||||
}
|
||||
}
|
||||
|
||||
// if we haven't cached an archive of the data view, do it now
|
||||
if (!_dataViewData[viewUID])
|
||||
_dataViewData[viewUID] = [CPKeyedArchiver archivedDataWithRootObject:view];
|
||||
|
||||
// unarchive the data view cache
|
||||
var newView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[viewUID]];
|
||||
|
||||
// map the new view's UID to it's data view prototype
|
||||
_dataViewForView[[newView UID]] = view;
|
||||
|
||||
CPLog.warn("creating cell: %s", newView);
|
||||
|
||||
return newView;
|
||||
}
|
||||
|
||||
- (void)_purge
|
||||
{
|
||||
for (var viewUID in _purgableInfosForDataView)
|
||||
{
|
||||
var purgableInfos = _purgableInfosForDataView[viewUID];
|
||||
|
||||
for (var key in purgableInfos)
|
||||
{
|
||||
var view = PurgableInfoView(purgableInfos[key]);
|
||||
|
||||
if (!view)
|
||||
CPLog.info("key="+key+" view=" + view + " purgableInfos[key]="+purgableInfos[key])
|
||||
else if (view._superview) {
|
||||
//CPLog.error("PURGING: (removing)" + view);
|
||||
//[view removeFromSuperview];
|
||||
[view setHidden:YES];
|
||||
}
|
||||
//else
|
||||
// CPLog.warn("PURGING: (already removed)" + view);
|
||||
|
||||
//delete purgableInfos[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
CPTableColumnHeaderViewKey = @"CPTableColumnHeaderViewKey",
|
||||
CPTableColumnDataViewKey = @"CPTableColumnDataViewKey",
|
||||
CPTableColumnWidthKey = @"CPTableColumnWidthKey",
|
||||
CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey",
|
||||
CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey",
|
||||
CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey";
|
||||
|
||||
@implementation CPTableColumn (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[self _init];
|
||||
|
||||
_identifier = [aCoder decodeObjectForKey:CPTableColumnIdentifierKey];
|
||||
|
||||
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
||||
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
|
||||
|
||||
_width = [aCoder decodeFloatForKey:CPTableColumnWidthKey];
|
||||
_minWidth = [aCoder decodeFloatForKey:CPTableColumnMinWidthKey];
|
||||
_maxWidth = [aCoder decodeFloatForKey:CPTableColumnMaxWidthKey];
|
||||
|
||||
_resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_identifier forKey:CPTableColumnIdentifierKey];
|
||||
|
||||
[aCoder encodeObject:_headerView forKey:CPTableColumnHeaderViewKey];
|
||||
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
|
||||
|
||||
[aCoder encodeObject:_width forKey:CPTableColumnWidthKey];
|
||||
[aCoder encodeObject:_minWidth forKey:CPTableColumnMinWidthKey];
|
||||
[aCoder encodeObject:_maxWidth forKey:CPTableColumnMaxWidthKey];
|
||||
|
||||
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
|
||||
}
|
||||
|
||||
@end
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,48 +1,82 @@
|
||||
/*
|
||||
* CPPlatform.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2010, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
#include "Platform.h"
|
||||
|
||||
|
||||
@implementation CPPlatform : CPObject
|
||||
@implementation CPBasePlatform : CPObject
|
||||
{
|
||||
}
|
||||
|
||||
+ (void)bootstrap
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
var body = document.getElementsByTagName("body")[0];
|
||||
|
||||
body.innerHTML = ""; // Get rid of anything that might be lingering in the body element.
|
||||
body.style.overflow = "hidden";
|
||||
|
||||
if (document.documentElement)
|
||||
document.documentElement.style.overflow = "hidden";
|
||||
#endif
|
||||
|
||||
[CPPlatformString bootstrap];
|
||||
[CPPlatformWindow setPrimaryPlatformWindow:[[CPPlatformWindow alloc] _init]];
|
||||
}
|
||||
|
||||
+ (BOOL)isBrowser
|
||||
{
|
||||
return typeof window.cpIsDesktop === "undefined";
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsDragAndDrop
|
||||
{
|
||||
return CPFeatureIsCompatible(CPHTMLDragAndDropFeature);
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsNativeMainMenu
|
||||
{
|
||||
return (typeof window["cpSetMainMenu"] === "function");
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (void)terminateApplication
|
||||
{
|
||||
if (typeof window["cpTerminate"] === "function")
|
||||
window.cpTerminate();
|
||||
}
|
||||
|
||||
+ (void)activateIgnoringOtherApps:(BOOL)shouldIgnoreOtherApps
|
||||
{
|
||||
}
|
||||
|
||||
+ (void)deactivate
|
||||
{
|
||||
}
|
||||
|
||||
+ (void)hideOtherApplications:(id)aSender
|
||||
{
|
||||
}
|
||||
|
||||
+ (void)hide:(id)aSender
|
||||
{
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
#include "DOM/CPPlatform.j"
|
||||
#else
|
||||
@implementation CPPlatform : CPBasePlatform
|
||||
{
|
||||
}
|
||||
@end
|
||||
#endif
|
||||
@@ -1,4 +1,24 @@
|
||||
|
||||
/*
|
||||
* CPPlatformString.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2010, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@@ -6,99 +26,26 @@
|
||||
#include "Platform.h"
|
||||
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
var DOMIFrameElement = nil,
|
||||
DOMSpanElement = nil,
|
||||
DefaultFont = nil;
|
||||
#endif
|
||||
|
||||
@implementation CPPlatformString : CPObject
|
||||
@implementation CPBasePlatformString : CPObject
|
||||
{
|
||||
}
|
||||
|
||||
+ (void)bootstrap
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
DOMIFrameElement = document.createElement("iframe");
|
||||
|
||||
DOMIFrameElement.name = name = "iframe_" + FLOOR(RAND() * 10000);
|
||||
DOMIFrameElement.style.position = "absolute";
|
||||
DOMIFrameElement.style.left = "-100px";
|
||||
DOMIFrameElement.style.top = "-100px";
|
||||
DOMIFrameElement.style.width = "1px";
|
||||
DOMIFrameElement.style.height = "1px";
|
||||
DOMIFrameElement.style.borderWidth = "0px";
|
||||
DOMIFrameElement.style.background = "blue";
|
||||
DOMIFrameElement.style.overflow = "hidden";
|
||||
DOMIFrameElement.style.zIndex = 100000000000;
|
||||
|
||||
document.getElementsByTagName("body")[0].appendChild(DOMIFrameElement);
|
||||
|
||||
var DOMIFrameDocument = (DOMIFrameElement.contentDocument || DOMIFrameElement.contentWindow.document);
|
||||
|
||||
DOMIFrameDocument.write("<html><head></head><body></body></html>");
|
||||
DOMIFrameDocument.close();
|
||||
|
||||
DOMSpanElement = DOMIFrameDocument.createElement("span");
|
||||
|
||||
DOMSpanElement.style.position = "absolute";
|
||||
DOMSpanElement.style.whiteSpace = "pre";
|
||||
DOMSpanElement.style.visibility = "visible";
|
||||
DOMSpanElement.style.padding = "0px";
|
||||
DOMSpanElement.style.margin = "0px";
|
||||
DOMSpanElement.style.background = "red";
|
||||
|
||||
DOMIFrameDocument.getElementsByTagName("body")[0].appendChild(DOMSpanElement);
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (CGSize)sizeOfString:(CPString)aString withFont:(CPFont)aFont forWidth:(float)aWidth
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
if (!aFont)
|
||||
{
|
||||
if (!DefaultFont)
|
||||
DefaultFont = [CPFont systemFontOfSize:12.0];
|
||||
|
||||
aFont = DefaultFont;
|
||||
}
|
||||
|
||||
var style = DOMSpanElement.style;
|
||||
|
||||
if (aWidth === NULL)
|
||||
{
|
||||
style.width = "";
|
||||
style.whiteSpace = "pre";
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
style.width = ROUND(aWidth) + "px";
|
||||
|
||||
if (document.attachEvent)
|
||||
style.wordWrap = "break-word";
|
||||
|
||||
else
|
||||
{
|
||||
style.whiteSpace = "-o-pre-wrap";
|
||||
style.whiteSpace = "-pre-wrap";
|
||||
style.whiteSpace = "-moz-pre-wrap";
|
||||
style.whiteSpace = "pre-wrap";
|
||||
}
|
||||
}
|
||||
|
||||
style.font = [aFont cssString];
|
||||
|
||||
if (CPFeatureIsCompatible(CPJavascriptInnerTextFeature))
|
||||
DOMSpanElement.innerText = aString;
|
||||
|
||||
else if (CPFeatureIsCompatible(CPJavascriptTextContentFeature))
|
||||
DOMSpanElement.textContent = aString;
|
||||
|
||||
return _CGSizeMake(DOMSpanElement.clientWidth, DOMSpanElement.clientHeight);
|
||||
#else
|
||||
return _CGSizeMakeZero();
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
#include "DOM/CPPlatformString.j"
|
||||
#else
|
||||
@implementation CPPlatformString : CPBasePlatformString
|
||||
{
|
||||
}
|
||||
@end
|
||||
#endif
|
||||
@@ -1,3 +1,24 @@
|
||||
/*
|
||||
* CPPlatformWindow.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2010, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@@ -13,6 +34,7 @@ var PrimaryPlatformWindow = NULL;
|
||||
|
||||
CPInteger _level;
|
||||
BOOL _hasShadow;
|
||||
unsigned _shadowStyle;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
DOMWindow _DOMWindow;
|
||||
@@ -24,12 +46,17 @@ var PrimaryPlatformWindow = NULL;
|
||||
CPDictionary _windowLayers;
|
||||
|
||||
BOOL _mouseIsDown;
|
||||
BOOL _mouseDownIsRightClick;
|
||||
CPWindow _mouseDownWindow;
|
||||
CPTimeInterval _lastMouseUp;
|
||||
CPTimeInterval _lastMouseDown;
|
||||
|
||||
Object _charCodes;
|
||||
unsigned _keyCode;
|
||||
unsigned _lastKey;
|
||||
BOOL _capsLockActive;
|
||||
BOOL _ignoreNativeCopyOrCutEvent;
|
||||
BOOL _ignoreNativePastePreparation;
|
||||
|
||||
BOOL _DOMEventMode;
|
||||
|
||||
@@ -41,6 +68,11 @@ var PrimaryPlatformWindow = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (CPSet)visiblePlatformWindows
|
||||
{
|
||||
return [CPSet set];
|
||||
}
|
||||
|
||||
+ (CPPlatformWindow)primaryPlatformWindow
|
||||
{
|
||||
return PrimaryPlatformWindow;
|
||||
@@ -95,7 +127,7 @@ var PrimaryPlatformWindow = NULL;
|
||||
|
||||
frame.origin = CGPointMakeZero();
|
||||
|
||||
if ([CPMenu menuBarVisible])
|
||||
if ([CPMenu menuBarVisible] && [CPPlatformWindow primaryPlatformWindow] === self)
|
||||
{
|
||||
var menuBarHeight = [[CPApp mainMenu] menuBarHeight];
|
||||
|
||||
@@ -106,7 +138,7 @@ var PrimaryPlatformWindow = NULL;
|
||||
return frame;
|
||||
}
|
||||
|
||||
- (void)usableContentFrame
|
||||
- (CGRect)usableContentFrame
|
||||
{
|
||||
return [self visibleFrame];
|
||||
}
|
||||
@@ -149,6 +181,36 @@ var PrimaryPlatformWindow = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)deminiaturize:(id)sender
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
if (_DOMWindow && typeof _DOMWindow["cpDeminiaturize"] === "function")
|
||||
_DOMWindow.cpDeminiaturize();
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)miniaturize:(id)sender
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
if (_DOMWindow && typeof _DOMWindow["cpMiniaturize"] === "function")
|
||||
_DOMWindow.cpMiniaturize();
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)moveWindow:(CPWindow)aWindow fromLevel:(int)fromLevel toLevel:(int)toLevel
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
if (!aWindow._isVisible)
|
||||
return;
|
||||
|
||||
var fromLayer = [self layerAtLevel:fromLevel create:NO],
|
||||
toLayer = [self layerAtLevel:toLevel create:YES];
|
||||
|
||||
[fromLayer removeWindow:aWindow];
|
||||
[toLayer insertWindow:aWindow atIndex:CPNotFound];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)setLevel:(CPInteger)aLevel
|
||||
{
|
||||
_level = aLevel;
|
||||
@@ -169,6 +231,16 @@ var PrimaryPlatformWindow = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)setShadowStyle:(int)aStyle
|
||||
{
|
||||
_shadowStyle = aStyle;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
if (_DOMWindow && _DOMWindow.cpSetShadowStyle)
|
||||
_shadowStyle.cpSetShadowStyle(aStyle);
|
||||
#endif
|
||||
}
|
||||
|
||||
- (BOOL)supportsFullPlatformWindows
|
||||
{
|
||||
return [CPPlatform isBrowser];
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
count = _windows.length - 1;
|
||||
|
||||
CPDOMDisplayServerRemoveChild(_DOMElement, aWindow._DOMElement);
|
||||
|
||||
|
||||
[_windows removeObjectAtIndex:aWindow._index];
|
||||
|
||||
for (; index < count; ++index)
|
||||
@@ -107,11 +107,12 @@
|
||||
_windows[zIndex]._index = zIndex;
|
||||
_windows[zIndex]._DOMElement.style.zIndex = zIndex;
|
||||
}
|
||||
|
||||
// If the window is not already a resident of this layer, add it.
|
||||
if (!isVisible)
|
||||
if (aWindow._DOMElement.parentNode !== _DOMElement)
|
||||
{
|
||||
CPDOMDisplayServerAppendChild(_DOMElement, aWindow._DOMElement);
|
||||
|
||||
|
||||
aWindow._isVisible = YES;
|
||||
|
||||
if ([aWindow isFullBridge])
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* CPPlatform+DOM.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2010, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
if (typeof window["CPPlatformEnableHTMLDragAndDrop"] === "undefined")
|
||||
CPPlatformEnableHTMLDragAndDrop = NO;
|
||||
|
||||
CPPlatformDidClearBodyElementNotification = @"CPPlatformDidClearBodyElementNotification";
|
||||
CPPlatformWillClearBodyElementNotification = @"CPPlatformWillClearBodyElementNotification";
|
||||
|
||||
var screenNeedsInitialization = NO,
|
||||
mainBodyElement = nil,
|
||||
elementRemovalTest = new RegExp("\\bcpdontremove\\b", "g");
|
||||
|
||||
@implementation CPPlatform : CPBasePlatform
|
||||
{
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self !== [CPPlatform class])
|
||||
return;
|
||||
|
||||
screenNeedsInitialization = [CPPlatform isBrowser];
|
||||
|
||||
// We do this here because doing it later breaks IE.
|
||||
if (document.documentElement)
|
||||
document.documentElement.style.overflow = "hidden";
|
||||
|
||||
if ([CPPlatform isBrowser])
|
||||
window.onunload = function()
|
||||
{
|
||||
[CPApp terminate:nil];
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)isBrowser
|
||||
{
|
||||
return typeof window.cpIsDesktop === "undefined";
|
||||
}
|
||||
|
||||
+ (BOOL)supportsDragAndDrop
|
||||
{
|
||||
return CPFeatureIsCompatible(CPHTMLDragAndDropFeature) && (CPPlatformEnableHTMLDragAndDrop || ![self isBrowser]);
|
||||
}
|
||||
|
||||
+ (BOOL)supportsNativeMainMenu
|
||||
{
|
||||
return (typeof window["cpSetMainMenu"] === "function");
|
||||
}
|
||||
|
||||
+ (void)terminateApplication
|
||||
{
|
||||
if (typeof window["cpTerminate"] === "function")
|
||||
window.cpTerminate();
|
||||
}
|
||||
|
||||
+ (void)activateIgnoringOtherApps:(BOOL)shouldIgnoreOtherApps
|
||||
{
|
||||
if (typeof window["cpActivateIgnoringOtherApps"] === "function")
|
||||
window.cpActivateIgnoringOtherApps(!!shouldIgnoreOtherApps);
|
||||
}
|
||||
|
||||
+ (void)deactivate
|
||||
{
|
||||
if (typeof window["cpDeactivate"] === "function")
|
||||
window.cpDeactivate();
|
||||
}
|
||||
|
||||
+ (void)hideOtherApplications:(id)aSender
|
||||
{
|
||||
if (typeof window["cpHideOtherApplications"] === "function")
|
||||
window.cpHideOtherApplications();
|
||||
}
|
||||
|
||||
+ (void)hide:(id)aSender
|
||||
{
|
||||
if (typeof window["cpHide"] === "function")
|
||||
window.cpHide();
|
||||
}
|
||||
|
||||
+ (DOMElement)mainBodyElement
|
||||
{
|
||||
if (!mainBodyElement)
|
||||
mainBodyElement = document.getElementById("cappuccino-body") || document.body;
|
||||
|
||||
return mainBodyElement;
|
||||
}
|
||||
|
||||
+ (void)initializeScreenIfNecessary
|
||||
{
|
||||
if (!screenNeedsInitialization)
|
||||
return;
|
||||
|
||||
screenNeedsInitialization = NO;
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPPlatformWillClearBodyElementNotification
|
||||
object:self];
|
||||
|
||||
var bodyElement = [self mainBodyElement];
|
||||
|
||||
// Get rid of any of the original contents of the page.
|
||||
var children = bodyElement.childNodes,
|
||||
length = children.length;
|
||||
|
||||
while (length--)
|
||||
{
|
||||
var element = children[length];
|
||||
if (!element.className || element.className.match(elementRemovalTest) === null)
|
||||
bodyElement.removeChild(element);
|
||||
}
|
||||
|
||||
bodyElement.style.overflow = "hidden";
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPPlatformDidClearBodyElementNotification
|
||||
object:self];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* CPPlatformString.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2010, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "../CoreGraphics/CGGeometry.h"
|
||||
|
||||
var DOMFixedWidthSpanElement = nil,
|
||||
DOMFlexibleWidthSpanElement = nil,
|
||||
DOMIFrameElement = nil,
|
||||
DefaultFont = nil;
|
||||
|
||||
@implementation CPPlatformString : CPBasePlatformString
|
||||
{
|
||||
}
|
||||
|
||||
+ (void)bootstrap
|
||||
{
|
||||
[self createDOMElements];
|
||||
}
|
||||
|
||||
+ (void)createDOMElements
|
||||
{
|
||||
var style;
|
||||
|
||||
DOMIFrameElement = document.createElement("iframe");
|
||||
// necessary for Safari caching bug:
|
||||
DOMIFrameElement.name = "iframe_" + FLOOR(RAND() * 10000);
|
||||
DOMIFrameElement.className = "cpdontremove";
|
||||
|
||||
style = DOMIFrameElement.style;
|
||||
style.position = "absolute";
|
||||
style.left = "-100px";
|
||||
style.top = "-100px";
|
||||
style.width = "1px";
|
||||
style.height = "1px";
|
||||
style.borderWidth = "0px";
|
||||
style.overflow = "hidden";
|
||||
style.zIndex = 100000000000;
|
||||
|
||||
var bodyElement = [CPPlatform mainBodyElement];
|
||||
|
||||
bodyElement.appendChild(DOMIFrameElement);
|
||||
|
||||
var DOMIFrameDocument = (DOMIFrameElement.contentDocument || DOMIFrameElement.contentWindow.document);
|
||||
DOMIFrameDocument.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'+
|
||||
'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head></head><body></body></html>');
|
||||
DOMIFrameDocument.close();
|
||||
|
||||
// IE needs this wide <div> to prevent unwanted text wrapping:
|
||||
var DOMDivElement = DOMIFrameDocument.createElement("div");
|
||||
DOMDivElement.style.position = "absolute";
|
||||
DOMDivElement.style.width = "100000px";
|
||||
|
||||
DOMIFrameDocument.body.appendChild(DOMDivElement);
|
||||
|
||||
DOMFlexibleWidthSpanElement = DOMIFrameDocument.createElement("span");
|
||||
style = DOMFlexibleWidthSpanElement.style;
|
||||
style.position = "absolute";
|
||||
style.visibility = "visible";
|
||||
style.padding = "0px";
|
||||
style.margin = "0px";
|
||||
style.whiteSpace = "pre";
|
||||
|
||||
DOMFixedWidthSpanElement = DOMIFrameDocument.createElement("span");
|
||||
style = DOMFixedWidthSpanElement.style;
|
||||
style.display = "block";
|
||||
style.position = "absolute";
|
||||
style.visibility = "visible";
|
||||
style.padding = "0px";
|
||||
style.margin = "0px";
|
||||
style.width = "1px";
|
||||
style.wordWrap = "break-word";
|
||||
try
|
||||
{
|
||||
style.whiteSpace = "pre";
|
||||
style.whiteSpace = "-o-pre-wrap";
|
||||
style.whiteSpace = "-pre-wrap";
|
||||
style.whiteSpace = "-moz-pre-wrap";
|
||||
style.whiteSpace = "pre-wrap";
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
//some versions of IE throw exceptions for unsupported properties.
|
||||
style.whiteSpace = "pre";
|
||||
}
|
||||
|
||||
DOMDivElement.appendChild(DOMFlexibleWidthSpanElement);
|
||||
DOMDivElement.appendChild(DOMFixedWidthSpanElement);
|
||||
}
|
||||
|
||||
+ (CGSize)sizeOfString:(CPString)aString withFont:(CPFont)aFont forWidth:(float)aWidth
|
||||
{
|
||||
if (!aFont)
|
||||
{
|
||||
if (!DefaultFont)
|
||||
DefaultFont = [CPFont systemFontOfSize:12.0];
|
||||
|
||||
aFont = DefaultFont;
|
||||
}
|
||||
|
||||
if (!DOMIFrameElement)
|
||||
[self createDOMElements];
|
||||
|
||||
var span;
|
||||
if (!aWidth)
|
||||
span = DOMFlexibleWidthSpanElement;
|
||||
else
|
||||
{
|
||||
span = DOMFixedWidthSpanElement;
|
||||
span.style.width = ROUND(aWidth) + "px";
|
||||
}
|
||||
|
||||
span.style.font = [aFont cssString];
|
||||
|
||||
if (CPFeatureIsCompatible(CPJavascriptInnerTextFeature))
|
||||
span.innerText = aString;
|
||||
else if (CPFeatureIsCompatible(CPJavascriptTextContentFeature))
|
||||
span.textContent = aString;
|
||||
|
||||
return _CGSizeMake(span.clientWidth, span.clientHeight);
|
||||
}
|
||||
|
||||
@end
|
||||
File diff suppressed because it is too large.
Load diff
Loaded 100 of 612 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user