зеркало из https://github.com/github/Rebel.git
Merge pull request #132 from github/popover-edge-fixes
Use next edge when preferred edge rect would be out of bounds
This commit is contained in:
Коммит
4a5ffefa13
|
@ -70,7 +70,7 @@
|
||||||
} else {
|
} else {
|
||||||
NSView *button = sender;
|
NSView *button = sender;
|
||||||
self.RBLPopover.behavior = self.behavior;
|
self.RBLPopover.behavior = self.behavior;
|
||||||
[self.RBLPopover showRelativeToRect:CGRectZero ofView:button preferredEdge:(CGRectEdge)self.preferredEdge];
|
[self.RBLPopover showRelativeToRect:button.bounds ofView:button preferredEdge:(CGRectEdge)self.preferredEdge];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -177,11 +177,11 @@ static CGFloat RBLRectsGetMedianY(CGRect r1, CGRect r2) {
|
||||||
positioningRect = [positioningView bounds];
|
positioningRect = [positioningView bounds];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSRect windowRelativeRect = [positioningView convertRect:positioningRect toView:nil];
|
NSRect windowRelativeRect = [positioningView convertRect:[positioningView alignmentRectForFrame:positioningRect] toView:nil];
|
||||||
CGRect screenRect = [positioningView.window convertRectToScreen:windowRelativeRect];
|
CGRect screenRect = [positioningView.window convertRectToScreen:windowRelativeRect];
|
||||||
|
|
||||||
self.backgroundView.popoverOrigin = screenRect;
|
self.backgroundView.popoverOrigin = screenRect;
|
||||||
|
|
||||||
self.originalViewSize = self.contentViewController.view.frame.size;
|
self.originalViewSize = self.contentViewController.view.frame.size;
|
||||||
CGSize contentViewSize = (CGSizeEqualToSize(self.contentSize, CGSizeZero) ? self.contentViewController.view.frame.size : self.contentSize);
|
CGSize contentViewSize = (CGSizeEqualToSize(self.contentSize, CGSizeZero) ? self.contentViewController.view.frame.size : self.contentSize);
|
||||||
|
|
||||||
|
@ -269,19 +269,32 @@ static CGFloat RBLRectsGetMedianY(CGRect r1, CGRect r2) {
|
||||||
|
|
||||||
return proposedRect;
|
return proposedRect;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BOOL (^screenRectContainsRectEdge)(CGRectEdge) = ^ BOOL (CGRectEdge edge) {
|
||||||
|
CGRect proposedRect = popoverRectForEdge(edge);
|
||||||
|
NSRect screenRect = positioningView.window.screen.visibleFrame;
|
||||||
|
|
||||||
|
BOOL minYInBounds = (edge == CGRectMinYEdge && NSMinY(proposedRect) >= NSMinY(screenRect));
|
||||||
|
BOOL maxYInBounds = (edge == CGRectMaxYEdge && NSMaxY(proposedRect) <= NSMaxY(screenRect));
|
||||||
|
BOOL minXInBounds = (edge == CGRectMinXEdge && NSMinX(proposedRect) >= NSMinX(screenRect));
|
||||||
|
BOOL maxXInBounds = (edge == CGRectMaxXEdge && NSMaxX(proposedRect) <= NSMaxX(screenRect));
|
||||||
|
|
||||||
|
return minYInBounds || maxYInBounds || minXInBounds || maxXInBounds;
|
||||||
|
};
|
||||||
|
|
||||||
NSUInteger attemptCount = 0;
|
NSUInteger attemptCount = 0;
|
||||||
while (!checkPopoverSizeForScreenWithPopoverEdge(popoverEdge)) {
|
while (!checkPopoverSizeForScreenWithPopoverEdge(popoverEdge)) {
|
||||||
if (attemptCount >= 4) {
|
if (attemptCount >= 4) {
|
||||||
popoverEdge = preferredEdge;
|
popoverEdge = (screenRectContainsRectEdge(preferredEdge) ? preferredEdge : nextEdgeForEdge(preferredEdge));
|
||||||
|
|
||||||
return fitRectToScreen(popoverRectForEdge(popoverEdge));
|
return fitRectToScreen(popoverRectForEdge(popoverEdge));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
popoverEdge = nextEdgeForEdge(popoverEdge);
|
popoverEdge = nextEdgeForEdge(popoverEdge);
|
||||||
attemptCount ++;
|
attemptCount ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return popoverRectForEdge(popoverEdge);
|
return popoverRectForEdge(popoverEdge);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -289,7 +302,10 @@ static CGFloat RBLRectsGetMedianY(CGRect r1, CGRect r2) {
|
||||||
|
|
||||||
if (self.shown) {
|
if (self.shown) {
|
||||||
if (self.backgroundView.popoverEdge == popoverEdge) {
|
if (self.backgroundView.popoverEdge == popoverEdge) {
|
||||||
|
CGSize size = [self.backgroundView sizeForBackgroundViewWithContentSize:contentViewSize popoverEdge:popoverEdge];
|
||||||
|
self.backgroundView.frame = (NSRect){ .size = size };
|
||||||
[self.popoverWindow setFrame:popoverScreenRect display:YES];
|
[self.popoverWindow setFrame:popoverScreenRect display:YES];
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,9 +511,9 @@ static CGFloat const RBLPopoverBackgroundViewArrowWidth = 35.0;
|
||||||
|
|
||||||
CGRect windowRect = [self.window convertRectFromScreen:self.popoverOrigin];
|
CGRect windowRect = [self.window convertRectFromScreen:self.popoverOrigin];
|
||||||
CGRect originRect = [self convertRect:windowRect fromView:nil];
|
CGRect originRect = [self convertRect:windowRect fromView:nil];
|
||||||
CGFloat midOriginY = floor(RBLRectsGetMedianY(originRect, contentRect));
|
|
||||||
CGFloat midOriginX = floor(RBLRectsGetMedianX(originRect, contentRect));
|
CGFloat midOriginX = floor(RBLRectsGetMedianX(originRect, contentRect));
|
||||||
|
CGFloat midOriginY = floor(RBLRectsGetMedianY(originRect, contentRect));
|
||||||
|
|
||||||
CGFloat maxArrowX = 0.0;
|
CGFloat maxArrowX = 0.0;
|
||||||
CGFloat minArrowX = 0.0;
|
CGFloat minArrowX = 0.0;
|
||||||
CGFloat minArrowY = 0.0;
|
CGFloat minArrowY = 0.0;
|
||||||
|
@ -512,65 +528,79 @@ static CGFloat const RBLPopoverBackgroundViewArrowWidth = 35.0;
|
||||||
maxArrowX = floor(midOriginX + (self.arrowSize.width / 2.0));
|
maxArrowX = floor(midOriginX + (self.arrowSize.width / 2.0));
|
||||||
CGFloat maxPossible = (NSMaxX(contentRect) - RBLPopoverBackgroundViewBorderRadius);
|
CGFloat maxPossible = (NSMaxX(contentRect) - RBLPopoverBackgroundViewBorderRadius);
|
||||||
if (maxArrowX > maxPossible) {
|
if (maxArrowX > maxPossible) {
|
||||||
CGFloat delta = maxArrowX - maxPossible;
|
|
||||||
maxArrowX = maxPossible;
|
maxArrowX = maxPossible;
|
||||||
minArrowX = maxArrowX - (self.arrowSize.width - delta);
|
minArrowX = maxArrowX - self.arrowSize.width;
|
||||||
} else {
|
} else {
|
||||||
minArrowX = floor(midOriginX - (self.arrowSize.width / 2.0));
|
minArrowX = floor(midOriginX - (self.arrowSize.width / 2.0));
|
||||||
if (minArrowX < RBLPopoverBackgroundViewBorderRadius) {
|
if (minArrowX < RBLPopoverBackgroundViewBorderRadius) {
|
||||||
CGFloat delta = RBLPopoverBackgroundViewBorderRadius - minArrowX;
|
|
||||||
minArrowX = RBLPopoverBackgroundViewBorderRadius;
|
minArrowX = RBLPopoverBackgroundViewBorderRadius;
|
||||||
maxArrowX = minArrowX + (self.arrowSize.width - (delta * 2));
|
maxArrowX = minArrowX + self.arrowSize.width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
minArrowY = floor(midOriginY - (self.arrowSize.width / 2.0));
|
minArrowY = floor(midOriginY - (self.arrowSize.width / 2.0));
|
||||||
if (minArrowY < RBLPopoverBackgroundViewBorderRadius) {
|
if (minArrowY < RBLPopoverBackgroundViewBorderRadius) {
|
||||||
CGFloat delta = RBLPopoverBackgroundViewBorderRadius - minArrowY;
|
|
||||||
minArrowY = RBLPopoverBackgroundViewBorderRadius;
|
minArrowY = RBLPopoverBackgroundViewBorderRadius;
|
||||||
maxArrowY = minArrowY + (self.arrowSize.width - (delta * 2));
|
maxArrowY = minArrowY + self.arrowSize.width;
|
||||||
} else {
|
} else {
|
||||||
maxArrowY = floor(midOriginY + (self.arrowSize.width / 2.0));
|
maxArrowY = floor(midOriginY + (self.arrowSize.width / 2.0));
|
||||||
CGFloat maxPossible = (NSMaxY(contentRect) - RBLPopoverBackgroundViewBorderRadius);
|
CGFloat maxPossible = (NSMaxY(contentRect) - RBLPopoverBackgroundViewBorderRadius);
|
||||||
if (maxArrowY > maxPossible) {
|
if (maxArrowY > maxPossible) {
|
||||||
CGFloat delta = maxArrowY - maxPossible;
|
|
||||||
maxArrowY = maxPossible;
|
maxArrowY = maxPossible;
|
||||||
minArrowY = maxArrowY - (self.arrowSize.width - delta);
|
minArrowY = maxArrowY - self.arrowSize.width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These represent the centerpoints of the popover's corner arcs.
|
||||||
|
CGFloat minCenterpointX = floor(minX + RBLPopoverBackgroundViewBorderRadius);
|
||||||
|
CGFloat maxCenterpointX = floor(maxX - RBLPopoverBackgroundViewBorderRadius);
|
||||||
|
CGFloat minCenterpointY = floor(minY + RBLPopoverBackgroundViewBorderRadius);
|
||||||
|
CGFloat maxCenterpointY = floor(maxY - RBLPopoverBackgroundViewBorderRadius);
|
||||||
|
|
||||||
CGMutablePathRef path = CGPathCreateMutable();
|
CGMutablePathRef path = CGPathCreateMutable();
|
||||||
CGPathMoveToPoint(path, NULL, minX, floor(minY + RBLPopoverBackgroundViewBorderRadius));
|
CGPathMoveToPoint(path, NULL, minX, minCenterpointY);
|
||||||
if (arrowEdge == CGRectMinXEdge) {
|
|
||||||
CGPathAddLineToPoint(path, NULL, minX, minArrowY);
|
CGFloat radius = RBLPopoverBackgroundViewBorderRadius;
|
||||||
CGPathAddLineToPoint(path, NULL, floor(minX - self.arrowSize.height), midOriginY);
|
|
||||||
CGPathAddLineToPoint(path, NULL, minX, maxArrowY);
|
CGPathAddArc(path, NULL, minCenterpointX, maxCenterpointY, radius, M_PI, M_PI_2, true);
|
||||||
|
|
||||||
|
CGPathAddArc(path, NULL, maxCenterpointX, maxCenterpointY, radius, M_PI_2, 0, true);
|
||||||
|
|
||||||
|
CGPathAddArc(path, NULL, maxCenterpointX, minCenterpointY, radius, 0, -M_PI_2, true);
|
||||||
|
|
||||||
|
CGPathAddArc(path, NULL, minCenterpointX, minCenterpointY, radius, -M_PI_2, M_PI, true);
|
||||||
|
|
||||||
|
CGPoint minBasePoint, tipPoint, maxBasePoint;
|
||||||
|
switch (arrowEdge) {
|
||||||
|
case CGRectMinXEdge:
|
||||||
|
minBasePoint = CGPointMake(minX, minArrowY);
|
||||||
|
tipPoint = CGPointMake(floor(minX - self.arrowSize.height), floor((minArrowY + maxArrowY) / 2));
|
||||||
|
maxBasePoint = CGPointMake(minX, maxArrowY);
|
||||||
|
break;
|
||||||
|
case CGRectMaxYEdge:
|
||||||
|
minBasePoint = CGPointMake(minArrowX, maxY);
|
||||||
|
tipPoint = CGPointMake(floor((minArrowX + maxArrowX) / 2), floor(maxY + self.arrowSize.height));
|
||||||
|
maxBasePoint = CGPointMake(maxArrowX, maxY);
|
||||||
|
break;
|
||||||
|
case CGRectMaxXEdge:
|
||||||
|
minBasePoint = CGPointMake(maxX, minArrowY);
|
||||||
|
tipPoint = CGPointMake(floor(maxX + self.arrowSize.height), floor((minArrowY + maxArrowY) / 2));
|
||||||
|
maxBasePoint = CGPointMake(maxX, maxArrowY);
|
||||||
|
break;
|
||||||
|
case CGRectMinYEdge:
|
||||||
|
minBasePoint = CGPointMake(minArrowX, minY);
|
||||||
|
tipPoint = CGPointMake(floor((minArrowX + maxArrowX) / 2), floor(minY - self.arrowSize.height));
|
||||||
|
maxBasePoint = CGPointMake(maxArrowX, minY);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGPathAddArc(path, NULL, floor(minX + RBLPopoverBackgroundViewBorderRadius), floor(minY + contentRect.size.height - RBLPopoverBackgroundViewBorderRadius), RBLPopoverBackgroundViewBorderRadius, M_PI, M_PI / 2, 1);
|
CGPathMoveToPoint(path, NULL, minBasePoint.x, minBasePoint.y);
|
||||||
if (arrowEdge == CGRectMaxYEdge) {
|
CGPathAddLineToPoint(path, NULL, tipPoint.x, tipPoint.y);
|
||||||
CGPathAddLineToPoint(path, NULL, minArrowX, maxY);
|
CGPathAddLineToPoint(path, NULL, maxBasePoint.x, maxBasePoint.y);
|
||||||
CGPathAddLineToPoint(path, NULL, midOriginX, floor(maxY + self.arrowSize.height));
|
|
||||||
CGPathAddLineToPoint(path, NULL, maxArrowX, maxY);
|
|
||||||
}
|
|
||||||
|
|
||||||
CGPathAddArc(path, NULL, floor(minX + contentRect.size.width - RBLPopoverBackgroundViewBorderRadius), floor(minY + contentRect.size.height - RBLPopoverBackgroundViewBorderRadius), RBLPopoverBackgroundViewBorderRadius, M_PI / 2, 0.0, 1);
|
|
||||||
if (arrowEdge == CGRectMaxXEdge) {
|
|
||||||
CGPathAddLineToPoint(path, NULL, maxX, maxArrowY);
|
|
||||||
CGPathAddLineToPoint(path, NULL, floor(maxX + self.arrowSize.height), midOriginY);
|
|
||||||
CGPathAddLineToPoint(path, NULL, maxX, minArrowY);
|
|
||||||
}
|
|
||||||
|
|
||||||
CGPathAddArc(path, NULL, floor(contentRect.origin.x + contentRect.size.width - RBLPopoverBackgroundViewBorderRadius), floor(minY + RBLPopoverBackgroundViewBorderRadius), RBLPopoverBackgroundViewBorderRadius, 0.0, -M_PI / 2, 1);
|
|
||||||
if (arrowEdge == CGRectMinYEdge) {
|
|
||||||
CGPathAddLineToPoint(path, NULL, maxArrowX, minY);
|
|
||||||
CGPathAddLineToPoint(path, NULL, midOriginX, floor(minY - self.arrowSize.height));
|
|
||||||
CGPathAddLineToPoint(path, NULL, minArrowX, minY);
|
|
||||||
}
|
|
||||||
|
|
||||||
CGPathAddArc(path, NULL, floor(minX + RBLPopoverBackgroundViewBorderRadius), floor(minY + RBLPopoverBackgroundViewBorderRadius), RBLPopoverBackgroundViewBorderRadius, -M_PI / 2, M_PI, 1);
|
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче