mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-10-10 10:42:19 +00:00
CPPopover fixes/enhancements
- Lion-style popovers now zoom open just like their Lion counterparts (except for opacity, the browser couldn't handle that at the same time). - Fixed a number of subtle drawing issues caused by not aligning path points correctly. - The anchor arrow deals correctly with corner cases where the middle of the reference rect is not within the corners of the popover. - Code cleanup: factored redundant code, removed unused code. - Added corner cases to the demo app, changed demo app to reuse a single popover.
This commit is contained in:
1 parent
28ed2f9bd0
commit
1a8fc7f07f
3 files changed
+381
-222
No files matched your search
@@ -22,11 +22,15 @@
|
||||
|
||||
@import "_CPWindowView.j"
|
||||
|
||||
#define ALIGN_STROKE(point) (FLOOR(point) === (point) ? (point) + halfStrokeWidth : (point))
|
||||
#define ALIGN_COORD(point) (FLOOR(point))
|
||||
|
||||
var _CPAttachedWindowViewDefaultCursorSize = CGSizeMake(16, 10);
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
|
||||
A custom CPWindowView that manage border and cursor
|
||||
A custom CPWindowView that manages a border and cursor
|
||||
*/
|
||||
@implementation _CPAttachedWindowView : _CPWindowView
|
||||
{
|
||||
@@ -36,7 +40,7 @@
|
||||
int _appearance @accessors(property=appearance);
|
||||
unsigned _preferredEdge @accessors(property=preferredEdge);
|
||||
|
||||
CPSize _cursorSize;
|
||||
CGSize _cursorSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -81,18 +85,16 @@
|
||||
/*!
|
||||
Initialize the _CPWindowView
|
||||
*/
|
||||
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
|
||||
- (id)initWithFrame:(CGRect)aFrame styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame styleMask:aStyleMask])
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[self class]];
|
||||
_arrowOffsetX = 0.0;
|
||||
_arrowOffsetY = 0.0;
|
||||
|
||||
// @TODO: make this themable
|
||||
_useGlowingEffect = YES;
|
||||
_appearance = CPPopoverAppearanceMinimal;
|
||||
_cursorSize = CPSizeMake(15, 10);
|
||||
_cursorSize = CGSizeMakeCopy(_CPAttachedWindowViewDefaultCursorSize);
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -103,7 +105,7 @@
|
||||
*/
|
||||
- (void)hideCursor
|
||||
{
|
||||
_cursorSize = CPSizeMakeZero();
|
||||
_cursorSize = CGSizeMakeZero();
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
@@ -112,7 +114,7 @@
|
||||
*/
|
||||
- (void)showCursor
|
||||
{
|
||||
_cursorSize = CPSizeMake(15, 10);
|
||||
_cursorSize = CGSizeMakeCopy(_CPAttachedWindowViewDefaultCursorSize);
|
||||
[self setNeedsDisplay:YES];
|
||||
_mouseDownPressed = NO;
|
||||
}
|
||||
@@ -129,11 +131,13 @@
|
||||
arrowWidth = _cursorSize.width,
|
||||
arrowHeight = _cursorSize.height,
|
||||
strokeWidth = 1,
|
||||
halfStrokeWidth = strokeWidth / 2.0,
|
||||
strokeColor,
|
||||
shadowColor = [[CPColor blackColor] colorWithAlphaComponent:.2],
|
||||
shadowSize = CGSizeMake(0, 7),
|
||||
shadowSize = CGSizeMake(0, 6),
|
||||
shadowBlur = 15,
|
||||
gradient;
|
||||
gradient,
|
||||
frame = [self bounds];
|
||||
|
||||
if (_appearance == CPPopoverAppearanceMinimal)
|
||||
{
|
||||
@@ -149,133 +153,217 @@
|
||||
}
|
||||
|
||||
// fix rect to take care of stroke and shadow
|
||||
aRect.origin.x += strokeWidth + shadowBlur;
|
||||
aRect.origin.y += strokeWidth + (shadowBlur + shadowSize.height / 2);
|
||||
aRect.size.width -= (strokeWidth * 2) + (shadowBlur * 2);
|
||||
aRect.size.height -= (strokeWidth * 2) + (shadowBlur * 2 + shadowSize.height);
|
||||
frame.origin.x += halfStrokeWidth + shadowBlur;
|
||||
frame.origin.y += halfStrokeWidth + (shadowBlur + shadowSize.height / 2);
|
||||
frame.size.width -= strokeWidth + (shadowBlur * 2);
|
||||
frame.size.height -= strokeWidth + (shadowBlur * 2 + shadowSize.height);
|
||||
|
||||
CGContextSetStrokeColor(context, strokeColor);
|
||||
CGContextSetLineWidth(context, strokeWidth);
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetShadowWithColor(context, shadowSize, shadowBlur, shadowColor);
|
||||
CGContextDrawLinearGradient(context, gradient, CGPointMake(CPRectGetMidX(aRect), 0.0), CGPointMake(CPRectGetMidX(aRect), aRect.size.height), 0);
|
||||
CGContextDrawLinearGradient(context, gradient, CGPointMake(CGRectGetMidX(frame), 0.0), CGPointMake(CGRectGetMidX(frame), frame.size.height), 0);
|
||||
|
||||
|
||||
var xMin = _CGRectGetMinX(aRect),
|
||||
xMax = _CGRectGetMaxX(aRect),
|
||||
yMin = _CGRectGetMinY(aRect),
|
||||
yMax = _CGRectGetMaxY(aRect);
|
||||
var xMin = _CGRectGetMinX(frame),
|
||||
xMax = _CGRectGetMaxX(frame),
|
||||
yMin = _CGRectGetMinY(frame),
|
||||
yMax = _CGRectGetMaxY(frame),
|
||||
arrowMinX = ALIGN_COORD(xMin + radius + strokeWidth),
|
||||
arrowMaxX = ALIGN_COORD(xMax - radius - strokeWidth),
|
||||
arrowMinY = ALIGN_COORD(yMin + radius + strokeWidth),
|
||||
arrowMaxY = ALIGN_COORD(yMax - radius + strokeWidth),
|
||||
arrowAnchor = CGPointMakeZero(),
|
||||
arrowStart = CGPointMakeZero(),
|
||||
pt = CGPointMakeZero();
|
||||
|
||||
// draw!
|
||||
switch (_preferredEdge)
|
||||
{
|
||||
case CPMinXEdge:
|
||||
// origin ne
|
||||
CGContextMoveToPoint(context, xMin + radius, yMin);
|
||||
|
||||
// ne
|
||||
CGContextAddLineToPoint(context, xMax - radius, yMin);
|
||||
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
|
||||
|
||||
// arrow CPMinXEdge
|
||||
CGContextAddLineToPoint(context, xMax, (aRect.size.height / 2) + aRect.origin.y + _arrowOffsetY - (arrowHeight - 2));
|
||||
CGContextAddLineToPoint(context, aRect.size.width + arrowHeight + aRect.origin.x + _arrowOffsetX, (aRect.size.height / 2) + aRect.origin.y + _arrowOffsetY);
|
||||
CGContextAddLineToPoint(context, aRect.size.width + aRect.origin.x + _arrowOffsetX, (aRect.size.height / 2 + (arrowWidth / 2)) + aRect.origin.y + _arrowOffsetY);
|
||||
|
||||
// se
|
||||
CGContextAddLineToPoint(context, xMax, yMax - radius);
|
||||
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
|
||||
|
||||
// sw
|
||||
CGContextAddLineToPoint(context, xMin + radius, yMax);
|
||||
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
|
||||
|
||||
// nw
|
||||
CGContextAddLineToPoint(context, xMin, yMin + radius);
|
||||
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
|
||||
break;
|
||||
|
||||
case CPMaxXEdge:
|
||||
// origin ne
|
||||
CGContextMoveToPoint(context, xMin + radius, yMin);
|
||||
// origin nw
|
||||
pt.x = ALIGN_COORD(xMin + radius);
|
||||
pt.y = yMin;
|
||||
CGContextMoveToPoint(context, pt.x, pt.y);
|
||||
|
||||
// ne
|
||||
CGContextAddLineToPoint(context, xMax - radius, yMin);
|
||||
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
|
||||
pt.x = ALIGN_COORD(xMax - radius);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, xMax, yMin, xMax, ALIGN_COORD(yMin + radius));
|
||||
|
||||
if (_preferredEdge === CPMinXEdge)
|
||||
{
|
||||
// arrow CPMinXEdge
|
||||
arrowAnchor.x = ALIGN_STROKE(xMax);
|
||||
arrowAnchor.y = ALIGN_COORD((frame.size.height / 2) + yMin + _arrowOffsetY);
|
||||
|
||||
// to top edge
|
||||
pt.y = ALIGN_COORD(arrowAnchor.y - (arrowWidth / 2));
|
||||
|
||||
// adjust starting point to not go beyond the corner
|
||||
if (pt.y <= arrowMinY)
|
||||
pt.y = arrowMinY;
|
||||
else if ((pt.y + arrowWidth) > arrowMaxY)
|
||||
pt.y = arrowMaxY - arrowWidth;
|
||||
|
||||
pt.x = arrowAnchor.x;
|
||||
arrowStart = CGPointMakeCopy(pt);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// top edge -> point
|
||||
pt.x = ALIGN_STROKE(arrowAnchor.x + arrowHeight);
|
||||
pt.y = arrowAnchor.y;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// point -> bottom edge
|
||||
pt.x = arrowAnchor.x;
|
||||
pt.y = ALIGN_COORD(arrowStart.y + arrowWidth);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
}
|
||||
|
||||
// se
|
||||
CGContextAddLineToPoint(context, xMax, yMax - radius);
|
||||
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
|
||||
pt.x = xMax;
|
||||
pt.y = ALIGN_COORD(yMax - radius);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, pt.x, yMax, ALIGN_COORD(xMax - radius), yMax);
|
||||
|
||||
// sw
|
||||
CGContextAddLineToPoint(context, xMin + radius, yMax);
|
||||
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
|
||||
pt.x = ALIGN_COORD(xMin + radius);
|
||||
pt.y = yMax;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, xMin, pt.y, xMin, ALIGN_COORD(yMax - radius));
|
||||
|
||||
// arrow CPMaxXEdge
|
||||
CGContextAddLineToPoint(context, xMin, (aRect.size.height / 2 + (arrowWidth / 2) + aRect.origin.y + _arrowOffsetY));
|
||||
CGContextAddLineToPoint(context, aRect.origin.x - arrowHeight + _arrowOffsetX, (aRect.size.height / 2) + aRect.origin.y + _arrowOffsetY);
|
||||
CGContextAddLineToPoint(context, aRect.origin.x + _arrowOffsetX, (aRect.size.height / 2 - (arrowWidth / 2) + aRect.origin.y + _arrowOffsetY));
|
||||
if (_preferredEdge === CPMaxXEdge)
|
||||
{
|
||||
// arrow CPMaxXEdge
|
||||
arrowAnchor.x = ALIGN_STROKE(xMin);
|
||||
arrowAnchor.y = ALIGN_COORD((frame.size.height / 2) + yMin + _arrowOffsetY);
|
||||
|
||||
// to bottom edge
|
||||
pt.y = ALIGN_COORD(arrowAnchor.y + (arrowWidth / 2));
|
||||
|
||||
// adjust starting point to not go beyond the corner
|
||||
if ((pt.y - arrowWidth) < arrowMinY)
|
||||
pt.y = arrowMinY + arrowWidth;
|
||||
else if (pt.y > arrowMaxY)
|
||||
pt.y = arrowMaxY;
|
||||
|
||||
pt.x = arrowAnchor.x;
|
||||
arrowStart = CGPointMakeCopy(pt);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// bottom edge -> point
|
||||
pt.x = ALIGN_STROKE(arrowAnchor.x - arrowHeight);
|
||||
pt.y = arrowAnchor.y;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// point -> top edge
|
||||
pt.x = arrowAnchor.x;
|
||||
pt.y = ALIGN_COORD(arrowStart.y - arrowWidth);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
}
|
||||
|
||||
// nw
|
||||
CGContextAddLineToPoint(context, xMin, yMin + radius);
|
||||
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
|
||||
pt.x = xMin;
|
||||
pt.y = ALIGN_COORD(yMin + radius);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, pt.x, yMin, ALIGN_COORD(xMin + radius), yMin);
|
||||
break;
|
||||
|
||||
case CPMaxYEdge:
|
||||
// origin nw
|
||||
CGContextMoveToPoint(context, xMin, yMin + yMin);
|
||||
|
||||
// nw
|
||||
CGContextAddLineToPoint(context, xMin, yMin + radius);
|
||||
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
|
||||
|
||||
// arrow CPMaxYEdge
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) + aRect.origin.x + _arrowOffsetX - (arrowWidth / 2), yMin);
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) + aRect.origin.x + _arrowOffsetX, aRect.origin.y - arrowHeight + _arrowOffsetY);
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) + (arrowWidth / 2) + aRect.origin.x + _arrowOffsetX, aRect.origin.y + _arrowOffsetY);
|
||||
|
||||
// ne
|
||||
CGContextAddLineToPoint(context, xMax - radius, yMin);
|
||||
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
|
||||
|
||||
// se
|
||||
CGContextAddLineToPoint(context, xMax, yMax - radius);
|
||||
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
|
||||
|
||||
// sw
|
||||
CGContextAddLineToPoint(context, xMin + radius, yMax);
|
||||
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
|
||||
break;
|
||||
|
||||
case CPMinYEdge:
|
||||
// origin nw
|
||||
CGContextMoveToPoint(context, xMin, yMin + yMin);
|
||||
// origin sw
|
||||
pt.x = xMin;
|
||||
pt.y = ALIGN_COORD(yMax - radius);
|
||||
CGContextMoveToPoint(context, pt.x, pt.y);
|
||||
|
||||
// nw
|
||||
CGContextAddLineToPoint(context, xMin, yMin + radius);
|
||||
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
|
||||
pt.y = ALIGN_COORD(yMin + radius);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, pt.x, yMin, ALIGN_COORD(xMin + radius), yMin);
|
||||
|
||||
if (_preferredEdge === CPMaxYEdge)
|
||||
{
|
||||
// arrow CPMaxYEdge
|
||||
arrowAnchor.x = ALIGN_COORD((frame.size.width / 2) + xMin + _arrowOffsetX);
|
||||
arrowAnchor.y = ALIGN_STROKE(yMin + _arrowOffsetY);
|
||||
|
||||
// to left edge
|
||||
pt.x = ALIGN_COORD(arrowAnchor.x - (arrowWidth / 2));
|
||||
|
||||
// adjust starting point to not go beyond the corner
|
||||
if (pt.x < arrowMinX)
|
||||
pt.x = arrowMinX;
|
||||
else if ((pt.x + arrowWidth) > arrowMaxX)
|
||||
pt.x = arrowMaxX - arrowWidth;
|
||||
|
||||
pt.y = arrowAnchor.y;
|
||||
arrowStart = CGPointMakeCopy(pt);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// left edge -> point
|
||||
pt.x = arrowAnchor.x;
|
||||
pt.y = ALIGN_STROKE(arrowAnchor.y - arrowHeight);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// point -> right edge
|
||||
pt.x = ALIGN_COORD(arrowStart.x + arrowWidth);
|
||||
pt.y = arrowAnchor.y;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
}
|
||||
|
||||
// ne
|
||||
CGContextAddLineToPoint(context, xMax - radius, yMin);
|
||||
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
|
||||
pt.x = ALIGN_COORD(xMax - radius);
|
||||
pt.y = yMin;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, xMax, pt.y, xMax, ALIGN_COORD(yMin + radius));
|
||||
|
||||
// se
|
||||
CGContextAddLineToPoint(context, xMax, yMax - radius);
|
||||
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
|
||||
pt.x = xMax;
|
||||
pt.y = ALIGN_COORD(yMax - radius);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, pt.x, yMax, ALIGN_COORD(xMax - radius), yMax);
|
||||
|
||||
// arrow CPMinYEdge
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) + (arrowWidth / 2) + aRect.origin.x + _arrowOffsetX , yMax);
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) + aRect.origin.x + _arrowOffsetX, aRect.size.height + aRect.origin.y + arrowHeight + _arrowOffsetY);
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) - (arrowWidth / 2) + aRect.origin.x + _arrowOffsetX, aRect.size.height + aRect.origin.y + _arrowOffsetY);
|
||||
if (_preferredEdge === CPMinYEdge)
|
||||
{
|
||||
// arrow CPMinYEdge
|
||||
arrowAnchor.x = ALIGN_COORD((frame.size.width / 2) + xMin + _arrowOffsetX);
|
||||
arrowAnchor.y = ALIGN_STROKE(yMax + _arrowOffsetY);
|
||||
|
||||
// to right edge
|
||||
pt.x = ALIGN_COORD(arrowAnchor.x + (arrowWidth / 2));
|
||||
|
||||
// adjust starting point to not go beyond the corner
|
||||
if ((pt.x - arrowWidth) < arrowMinX)
|
||||
pt.x = arrowMinX + arrowWidth;
|
||||
else if (pt.x > arrowMaxX)
|
||||
pt.x = arrowMaxX;
|
||||
|
||||
pt.y = arrowAnchor.y;
|
||||
arrowStart = CGPointMakeCopy(pt);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// right edge -> point
|
||||
pt.x = arrowAnchor.x;
|
||||
pt.y = ALIGN_STROKE(arrowAnchor.y + arrowHeight);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// point -> left edge
|
||||
pt.x = ALIGN_COORD(arrowStart.x - arrowWidth);
|
||||
pt.y = arrowAnchor.y;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
}
|
||||
|
||||
// sw
|
||||
CGContextAddLineToPoint(context, xMin + radius, yMax);
|
||||
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
|
||||
pt.x = ALIGN_COORD(xMin + radius);
|
||||
pt.y = yMax;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, xMin, pt.y, xMin, ALIGN_COORD(yMax - radius));
|
||||
break;
|
||||
|
||||
default:
|
||||
// no computed edge means standard rounded rect
|
||||
CGContextAddPath(context, CGPathWithRoundedRectangleInRect(aRect, radius, radius, YES, YES, YES, YES));
|
||||
CGContextAddPath(context, CGPathWithRoundedRectangleInRect(frame, radius, radius, YES, YES, YES, YES));
|
||||
}
|
||||
|
||||
CGContextClosePath(context);
|
||||
|
||||
+94
-73
@@ -49,9 +49,9 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0,
|
||||
|
||||
BOOL _closeOnBlur;
|
||||
BOOL _isClosed;
|
||||
BOOL _browserAnimates;
|
||||
BOOL _shouldPerformAnimation;
|
||||
CPButton _closeButton;
|
||||
float _animationDuration;
|
||||
CPInteger _implementedDelegateMethods;
|
||||
}
|
||||
|
||||
@@ -128,18 +128,16 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0,
|
||||
{
|
||||
_animates = YES;
|
||||
_animationStyle = CPPopoverAnimationStyleLion;
|
||||
_animationDuration = 150;
|
||||
_closeOnBlur = (aStyleMask & CPClosableOnBlurWindowMask);
|
||||
_isClosed = NO;
|
||||
_browserAnimates = [self browserSupportsAnimation];
|
||||
_shouldPerformAnimation = _animates;
|
||||
|
||||
[self setLevel:CPStatusWindowLevel];
|
||||
[self setMovableByWindowBackground:YES];
|
||||
[self setHasShadow:NO];
|
||||
|
||||
_DOMElement.style.webkitBackfaceVisibility = "hidden";
|
||||
_DOMElement.style.webkitTransitionProperty = "-webkit-transform, opacity";
|
||||
_DOMElement.style.webkitTransitionDuration = _animationDuration + "ms";
|
||||
[self setCSS3Property:@"TransitionProperty" value:@"-webkit-transform, opacity"];
|
||||
|
||||
[_windowView setNeedsDisplay:YES];
|
||||
}
|
||||
@@ -247,23 +245,24 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0,
|
||||
originLeft = CGPointCreateCopy(aRect.origin),
|
||||
originRight = CGPointCreateCopy(aRect.origin),
|
||||
originTop = CGPointCreateCopy(aRect.origin),
|
||||
originBottom = CGPointCreateCopy(aRect.origin);
|
||||
originBottom = CGPointCreateCopy(aRect.origin),
|
||||
frameSize = [self frame].size;
|
||||
|
||||
// CPMaxXEdge
|
||||
originRight.x += aRect.size.width;
|
||||
originRight.y += (aRect.size.height / 2.0) - (CGRectGetHeight([self frame]) / 2.0);
|
||||
originRight.y += (aRect.size.height / 2.0) - (frameSize.height / 2.0);
|
||||
|
||||
// CPMinXEdge
|
||||
originLeft.x -= CGRectGetWidth([self frame]);
|
||||
originLeft.y += (aRect.size.height / 2.0) - (CGRectGetHeight([self frame]) / 2.0);
|
||||
originLeft.x -= frameSize.width;
|
||||
originLeft.y += (aRect.size.height / 2.0) - (frameSize.height / 2.0);
|
||||
|
||||
// CPMaxYEdge
|
||||
originBottom.x += aRect.size.width / 2.0 - CGRectGetWidth([self frame]) / 2.0;
|
||||
originBottom.x += aRect.size.width / 2.0 - frameSize.width / 2.0;
|
||||
originBottom.y += aRect.size.height;
|
||||
|
||||
// CPMinYEdge
|
||||
originTop.x += aRect.size.width / 2.0 - CGRectGetWidth([self frame]) / 2.0;
|
||||
originTop.y -= CGRectGetHeight([self frame]);
|
||||
originTop.x += aRect.size.width / 2.0 - frameSize.width / 2.0;
|
||||
originTop.y -= frameSize.height;
|
||||
|
||||
var requestedEdge = (anEdge !== nil) ? anEdge : CPMaxXEdge,
|
||||
requestedOrigin;
|
||||
@@ -301,20 +300,20 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0,
|
||||
[_windowView setArrowOffsetX:o.x];
|
||||
o.x = 0;
|
||||
}
|
||||
if (o.x + CGRectGetWidth([self frame]) > nativeRect.size.width)
|
||||
if (o.x + frameSize.width > nativeRect.size.width)
|
||||
{
|
||||
[_windowView setArrowOffsetX:(o.x + CGRectGetWidth([self frame]) - nativeRect.size.width)];
|
||||
o.x = nativeRect.size.width - CGRectGetWidth([self frame]);
|
||||
[_windowView setArrowOffsetX:(o.x + frameSize.width - nativeRect.size.width)];
|
||||
o.x = nativeRect.size.width - frameSize.width;
|
||||
}
|
||||
if (o.y < 0)
|
||||
{
|
||||
[_windowView setArrowOffsetY:o.y];
|
||||
o.y = 0;
|
||||
}
|
||||
if (o.y + CGRectGetHeight([self frame]) > nativeRect.size.height)
|
||||
if (o.y + frameSize.height > nativeRect.size.height)
|
||||
{
|
||||
[_windowView setArrowOffsetY:(CGRectGetHeight([self frame]) + o.y - nativeRect.size.height)];
|
||||
o.y = nativeRect.size.height - CGRectGetHeight([self frame]);
|
||||
[_windowView setArrowOffsetY:(frameSize.height + o.y - nativeRect.size.height)];
|
||||
o.y = nativeRect.size.height - frameSize.height;
|
||||
}
|
||||
|
||||
switch (g)
|
||||
@@ -324,7 +323,7 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0,
|
||||
return o;
|
||||
break;
|
||||
case CPMinXEdge:
|
||||
if ((o.x + _frame.size.width) <= aRect.origin.x)
|
||||
if ((o.x + frameSize.width) <= aRect.origin.x)
|
||||
return o;
|
||||
break;
|
||||
case CPMaxYEdge:
|
||||
@@ -332,7 +331,7 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0,
|
||||
return o;
|
||||
break;
|
||||
case CPMinYEdge:
|
||||
if ((o.y + _frame.size.height) <= aRect.origin.y)
|
||||
if ((o.y + frameSize.height) <= aRect.origin.y)
|
||||
return o;
|
||||
break;
|
||||
}
|
||||
@@ -403,6 +402,27 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0,
|
||||
[self makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)setCSS3Property:(CPString)property value:(CPString)value
|
||||
{
|
||||
_DOMElement.style['webkit' + property] = value;
|
||||
|
||||
// Support other browsers here eventually
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (BOOL)browserSupportsAnimation
|
||||
{
|
||||
return typeof(_DOMElement.style.webkitTransition) !== "undefined";
|
||||
|
||||
/*
|
||||
No others browsers supported yet.
|
||||
|
||||
typeof(_DOMElement.style.MozTransition) !== "undefined" ||
|
||||
typeof(_DOMElement.style.MsTransition) !== "undefined" ||
|
||||
typeof(_DOMElement.style.OTransition) !== "undefined";
|
||||
*/
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Actions
|
||||
@@ -443,63 +463,65 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0,
|
||||
{
|
||||
[super orderFront:aSender];
|
||||
|
||||
var transformOrigin = "50% 100%";
|
||||
|
||||
if (_animationStyle === CPPopoverAnimationStyleLion)
|
||||
if (_animates && _browserAnimates && _shouldPerformAnimation)
|
||||
{
|
||||
switch ([_windowView preferredEdge])
|
||||
{
|
||||
case CPMaxYEdge:
|
||||
var posX = 50 + (([_windowView arrowOffsetX] * 100) / _frame.size.width);
|
||||
transformOrigin = posX + "% 0%"; // 50 0
|
||||
break;
|
||||
case CPMinYEdge:
|
||||
var posX = 50 + (([_windowView arrowOffsetX] * 100) / _frame.size.width);
|
||||
transformOrigin = posX + "% 100%"; // 50 100
|
||||
break;
|
||||
case CPMinXEdge:
|
||||
var posY = 50 + (([_windowView arrowOffsetY] * 100) / _frame.size.height);
|
||||
transformOrigin = "100% " + posY + "%"; // 100 50
|
||||
break;
|
||||
case CPMaxXEdge:
|
||||
var posY = 50 + (([_windowView arrowOffsetY] * 100) / _frame.size.height);
|
||||
transformOrigin = "0% "+ posY + "%"; // 0 50
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// @TODO: implement for FF
|
||||
if (_animates && _shouldPerformAnimation && typeof(_DOMElement.style.webkitTransform) != "undefined")
|
||||
{
|
||||
_DOMElement.style.opacity = 0;
|
||||
|
||||
if (_animationStyle === CPPopoverAnimationStyleLion)
|
||||
{
|
||||
_DOMElement.style.webkitTransform = "scale(0)";
|
||||
_DOMElement.style.webkitTransformOrigin = transformOrigin;
|
||||
}
|
||||
var transformOrigin = "50% 100%",
|
||||
frame = [self frame],
|
||||
preferredEdge = [_windowView preferredEdge],
|
||||
posX;
|
||||
|
||||
window.setTimeout(function()
|
||||
{
|
||||
_DOMElement.style.opacity = 1;
|
||||
_DOMElement.style.height = _frame.size.height + @"px";
|
||||
_DOMElement.style.width = _frame.size.width + @"px";
|
||||
|
||||
if (_animationStyle === CPPopoverAnimationStyleLion)
|
||||
switch (preferredEdge)
|
||||
{
|
||||
_DOMElement.style.webkitTransform = "scale(1.1)";
|
||||
_DOMElement.style.webkitTransitionDuration = "250ms";
|
||||
_DOMElement.style.webkitTransitionTimingFunction = "ease-out";
|
||||
case CPMaxYEdge:
|
||||
case CPMinYEdge:
|
||||
posX = 50 + (([_windowView arrowOffsetX] * 100) / frame.size.width);
|
||||
transformOrigin = posX + "% " + (preferredEdge === CPMaxYEdge ? "0%" : "100%");
|
||||
break;
|
||||
|
||||
var transitionEndFunction = function()
|
||||
{
|
||||
_DOMElement.style.webkitTransform = "scale(1)";
|
||||
_DOMElement.removeEventListener("webkitTransitionEnd", transitionEndFunction, YES);
|
||||
};
|
||||
|
||||
_DOMElement.addEventListener("webkitTransitionEnd", transitionEndFunction, YES);
|
||||
case CPMinXEdge:
|
||||
case CPMaxXEdge:
|
||||
posY = 50 + (([_windowView arrowOffsetY] * 100) / frame.size.height);
|
||||
transformOrigin = (preferredEdge === CPMaxXEdge ? "0% " : "100% ") + posY + "%"; // 100 50
|
||||
break;
|
||||
}
|
||||
}, 0);
|
||||
|
||||
// This is the initial transform
|
||||
[self setCSS3Property:@"Transform" value:@"scale(0)"];
|
||||
[self setCSS3Property:@"TransformOrigin" value:transformOrigin];
|
||||
[self setCSS3Property:@"TransitionDuration" value:"0"];
|
||||
|
||||
window.setTimeout(function()
|
||||
{
|
||||
if (_animationStyle === CPPopoverAnimationStyleLion)
|
||||
{
|
||||
// We are watching opacity, so this triggers the next transition
|
||||
_DOMElement.style.opacity = 1;
|
||||
_DOMElement.style.height = frame.size.height + @"px";
|
||||
_DOMElement.style.width = frame.size.width + @"px";
|
||||
|
||||
// Set up the pop-out transition
|
||||
[self setCSS3Property:@"Transform" value:@"scale(1.1)"];
|
||||
[self setCSS3Property:@"TransitionDuration" value:@"200ms"];
|
||||
[self setCSS3Property:@"TransitionTimingFunction" value:@"ease-in"];
|
||||
|
||||
var transitionEndFunction = function()
|
||||
{
|
||||
_DOMElement.removeEventListener("webkitTransitionEnd", transitionEndFunction, YES);
|
||||
|
||||
// Now set up the pop-in to normal size transition
|
||||
[self setCSS3Property:@"Transform" value:@"scale(1)"];
|
||||
[self setCSS3Property:@"TransitionDuration" value:@"50ms"];
|
||||
[self setCSS3Property:@"TransitionTimingFunction" value:@"linear"];
|
||||
};
|
||||
|
||||
_DOMElement.addEventListener("webkitTransitionEnd", transitionEndFunction, YES);
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
else
|
||||
_DOMElement.style.opacity = 1;
|
||||
}
|
||||
|
||||
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_attachedWindowDidMove:) name:CPWindowDidMoveNotification object:self];
|
||||
@@ -516,11 +538,10 @@ var _CPAttachedWindow_attachedWindowShouldClose_ = 1 << 0,
|
||||
// set a close flag to avoid infinite loop
|
||||
_isClosed = YES;
|
||||
|
||||
if (_animates && typeof(_DOMElement.style.webkitTransform) != "undefined")
|
||||
if (_animates && _browserAnimates)
|
||||
{
|
||||
[self setCSS3Property:@"Transition" value:@"opacity 250ms linear"];
|
||||
_DOMElement.style.opacity = 0;
|
||||
_DOMElement.style.webkitTransitionDuration = "250ms";
|
||||
_DOMElement.style.webkitTransitionTimingFunction = "linear";
|
||||
|
||||
var transitionEndFunction = function()
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user