diff --git a/AppKit/CPAnimation.j b/AppKit/CPAnimation.j index 712d5f7af..032a05df9 100644 --- a/AppKit/CPAnimation.j +++ b/AppKit/CPAnimation.j @@ -300,13 +300,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)t1) {return t1;} + while(t0x2) {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)); +}; diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 688fd01d8..0b0d1bee0 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -176,13 +176,13 @@ CPWindowWillCloseNotification = @"CPWindowWillCloseNotification"; CPWindowDidBecomeMainNotification = @"CPWindowDidBecomeMainNotification"; CPWindowDidResignMainNotification = @"CPWindowDidResignMainNotification"; CPWindowDidMoveNotification = @"CPWindowDidMoveNotification"; - +CPWindowWillBeginSheetNotification = @"CPWindowWillBeginSheetNotification"; +CPWindowDidEndSheetNotification = @"CPWindowDidEndSheetNotification"; CPWindowShadowStyleStandard = 0; CPWindowShadowStyleMenu = 1; CPWindowShadowStylePanel = 2; - var SHADOW_MARGIN_LEFT = 20.0, SHADOW_MARGIN_RIGHT = 19.0, SHADOW_MARGIN_TOP = 10.0, @@ -311,6 +311,8 @@ var CPWindowSaveImage = nil, _CPWindowFullPlatformWindowSession _fullPlatformWindowSession; CPDictionary _sheetContext; + CPWindow _parentView; + BOOL _isSheet; } /* @@ -365,6 +367,7 @@ CPTexturedBackgroundWindowMask _isFullPlatformWindow = NO; _registeredDraggedTypes = [CPSet set]; _registeredDraggedTypesArray = []; + _isSheet = NO; // Set up our window number. _windowNumber = [CPApp._windows count]; @@ -1767,27 +1770,24 @@ CPTexturedBackgroundWindowMask frame = [self frame], sheetContent = [aSheet contentView]; - // Autoresizing [self _setUpMasksForView:sheetContent]; aSheet._isSheet = YES; aSheet._parentView = self; - // calculate start/end frames var originx = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width)/2), originy = frame.origin.y + [[self contentView] frame].origin.y, startFrame = CGRectMake(originx, originy, sheetFrame.size.width, 0), endFrame = CGRectMake(originx, originy, sheetFrame.size.width, sheetFrame.size.height); - [[CPNotificationCenter defaultCenter] postNotificationName:@"CPWindowWillBeginSheetNotification" object:self]; + [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillBeginSheetNotification object:self]; [CPApp runModalForWindow:aSheet]; - // Order front and animate the sheet [aSheet orderFront:self]; [aSheet setFrame:startFrame]; _sheetContext["opened"] = YES; - [aSheet _setFrame:endFrame delegate:self duration:0.3 curve:CPAnimationEaseOut]; + [aSheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseOut]; // Should run the main loop here until _isAnimating = FALSE [aSheet becomeKeyWindow]; @@ -1801,14 +1801,14 @@ CPTexturedBackgroundWindowMask endFrame = CGRectMakeCopy(startFrame); endFrame.size.height = 0; + _sheetContext["frame"] = startFrame; var sheetContent = [sheet contentView]; - [self _setUpMasksForView:sheetContent]; _sheetContext["opened"] = NO; - [sheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationLinear]; + [sheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseIn]; } /* @ignore */ @@ -1824,10 +1824,10 @@ CPTexturedBackgroundWindowMask { [self _restoreMasksForView:sheetContent]; return; - } - + } + [CPApp stopModal]; - [[CPNotificationCenter defaultCenter] postNotificationName:@"CPWindowDidEndSheetNotification" object:self]; + [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidEndSheetNotification object:self]; [sheet orderOut:self]; @@ -1837,11 +1837,11 @@ CPTexturedBackgroundWindowMask [self _restoreMasksForView:sheetContent]; var delegate = _sheetContext["modalDelegate"], - endSelector = _sheetContext["endSelector"]; + endSelector = _sheetContext["endSelector"]; if (delegate != nil && endSelector != nil) - objj_msgSend(_sheetContext["modalDelegate"], _sheetContext["endSelector"], sheet, _sheetContext["returnCode"], _sheetContext["contextInfo"]); - + objj_msgSend(delegate, endSelector, sheet, _sheetContext["returnCode"], _sheetContext["contextInfo"]); + _sheetContext = nil; sheet._parentView = nil; } diff --git a/Tests/AttachedSheet/AppController.j b/Tests/AttachedSheet/AppController.j new file mode 100644 index 000000000..d5ef53467 --- /dev/null +++ b/Tests/AttachedSheet/AppController.j @@ -0,0 +1,89 @@ +/* + * AppController.j + * AttachedSheet + * + * Created by Cacaodev on August 1, 2009. + * Copyright 2009, Your Company All rights reserved. + */ + +@import + +@implementation AppController : CPObject +{ + CPWindow window; + CPWindow sheet; + CPTextField textField; +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + window = [[CPWindow alloc] initWithContentRect:CGRectMake(100,100,500,300) styleMask:CPResizableWindowMask], + contentView = [window contentView]; + + sheet = [[CPWindow alloc] initWithContentRect:CGRectMake(0,0,300,100) styleMask:CPDocModalWindowMask|CPResizableWindowMask]; + // [sheet setMinSize:CGSizeMake(300,100)]; + + var sheetContent = [sheet contentView]; + + textField = [[CPTextField alloc] initWithFrame:CGRectMake(10,30,280,30)]; + [textField setEditable:YES]; + [textField setBezeled:YES]; + [textField setAutoresizingMask:CPViewWidthSizable]; + + var okButton = [[CPButton alloc] initWithFrame:CGRectMake(230,70,50,24)]; + [okButton setTitle:"OK"]; + [okButton setTarget:self]; + [okButton setTag:1]; + [okButton setAction:@selector(closeSheet:)]; + [okButton setAutoresizingMask:CPViewMinXMargin|CPViewMinYMargin]; + + var cancelButton = [[CPButton alloc] initWithFrame:CGRectMake(120,70,100,24)]; + [cancelButton setTitle:"Cancel"]; + [cancelButton setTarget:self]; + [cancelButton setTag:0]; + [cancelButton setAction:@selector(closeSheet:)]; + [cancelButton setAutoresizingMask:CPViewMinXMargin|CPViewMinYMargin]; + + [sheetContent addSubview:textField]; + [sheetContent addSubview:okButton]; + [sheetContent addSubview:cancelButton]; + + var displayButton = [[CPButton alloc] initWithFrame:CGRectMake(200,150,100,24)]; + [displayButton setTitle:"Display Sheet"]; + [displayButton setTarget:self]; + [displayButton setAction:@selector(displaySheet:)]; + [contentView addSubview:displayButton]; + + [window orderFront:self] +} + +- (void)displaySheet:(id)sender +{ + [textField setStringValue:""]; + [sheet makeFirstResponder:textField]; + + [CPApp beginSheet:sheet modalForWindow:window modalDelegate:self didEndSelector:@selector(didEndSheet:returnCode:contextInfo:) contextInfo:nil]; +} + +- (void)alertDidEnd:(CPWindow)sheet returnCode:(int)returnCode contextInfo:(id)contextInfo +{ + CPLogConsole(_cmd+" returnCode " + returnCode); +} + +- (void)closeSheet:(id)sender +{ + [CPApp endSheet:sheet returnCode:[sender tag]]; +} + +- (void)didEndSheet:(CPWindow)sheet returnCode:(int)returnCode contextInfo:(id)contextInfo +{ + var str = [textField stringValue]; + + [sheet orderOut:self]; + if (returnCode == CPOKButton && [str length] > 0) + { + [window setTitle:str]; + } +} + +@end \ No newline at end of file diff --git a/Tests/AttachedSheet/Info.plist b/Tests/AttachedSheet/Info.plist new file mode 100644 index 000000000..143e86dbd --- /dev/null +++ b/Tests/AttachedSheet/Info.plist @@ -0,0 +1,12 @@ + + + + + CPApplicationDelegateClass + AppController + CPBundleName + FullOfSheet + CPPrincipalClass + CPApplication + + diff --git a/Tests/AttachedSheet/Rakefile b/Tests/AttachedSheet/Rakefile new file mode 100644 index 000000000..3fc1dbfa1 --- /dev/null +++ b/Tests/AttachedSheet/Rakefile @@ -0,0 +1,25 @@ + +require 'objective-j' +require 'objective-j/bundletask' + +if !ENV['CONFIG'] + ENV['CONFIG'] = 'Debug' +end + +ObjectiveJ::BundleTask.new(:SplitView) do |t| + t.name = 'SplitView' + t.identifier = 'com.yourcompany.SplitView' + t.version = '1.0' + t.author = 'Your Company' + t.email = 'feedback @nospam@ yourcompany.com' + t.summary = 'SplitView' + t.sources = FileList['*.j'] + t.resources = FileList['Resources/*'] + t.index_file = 'index.html' + t.info_plist = 'Info.plist' + t.build_path = File.join('Build', ENV['CONFIG'], 'SplitView') + t.flag = '-DDEBUG' if ENV['CONFIG'] == 'Debug' + t.flag = '-O' if ENV['CONFIG'] == 'Release' +end + +task :default => [:SplitView] diff --git a/Tests/AttachedSheet/Resources/spinner.gif b/Tests/AttachedSheet/Resources/spinner.gif new file mode 100644 index 000000000..06dbc2bc2 Binary files /dev/null and b/Tests/AttachedSheet/Resources/spinner.gif differ diff --git a/Tests/AttachedSheet/index-debug.html b/Tests/AttachedSheet/index-debug.html new file mode 100644 index 000000000..4daefda17 --- /dev/null +++ b/Tests/AttachedSheet/index-debug.html @@ -0,0 +1,83 @@ + + + + + + + + Attached Sheet + + + + + + + + + + + + + +
+ + + +
+ + + diff --git a/Tests/AttachedSheet/index.html b/Tests/AttachedSheet/index.html new file mode 100644 index 000000000..d44a75d39 --- /dev/null +++ b/Tests/AttachedSheet/index.html @@ -0,0 +1,69 @@ + + + + + + + + Attached Sheet + + + + + + + + + + + + +
+ + + +
+ + + + diff --git a/Tests/AttachedSheet/main.j b/Tests/AttachedSheet/main.j new file mode 100755 index 000000000..b67c4550b --- /dev/null +++ b/Tests/AttachedSheet/main.j @@ -0,0 +1,18 @@ +/* + * AppController.j + * SplitView + * + * Created by You on August 1, 2009. + * Copyright 2009, Your Company All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +}