Authored by Justin R. Miller

fixes #159: programmatic callout display/dismiss & callout API improvements

@@ -330,6 +330,21 @@ typedef enum : NSUInteger { @@ -330,6 +330,21 @@ typedef enum : NSUInteger {
330 * @return The screen position of the annotation. */ 330 * @return The screen position of the annotation. */
331 - (CGPoint)mapPositionForAnnotation:(RMAnnotation *)annotation; 331 - (CGPoint)mapPositionForAnnotation:(RMAnnotation *)annotation;
332 332
  333 +/** Selects the specified annotation and displays a callout view for it.
  334 +*
  335 +* If the specified annotation is not onscreen, and therefore does not have an associated annotation layer, this method has no effect.
  336 +* @param annotation The annotation object to select.
  337 +* @param animated If `YES`, the callout view is animated into position. */
  338 +- (void)selectAnnotation:(RMAnnotation *)annotation animated:(BOOL)animated;
  339 +
  340 +/** Deselects the specified annotation and hides its callout view.
  341 +* @param annotation The annotation object to deselect.
  342 +* @param animated If `YES`, the callout view is animated offscreen. */
  343 +- (void)deselectAnnotation:(RMAnnotation *)annotation animated:(BOOL)animated;
  344 +
  345 +/** The annotation that is currently selected. */
  346 +@property (nonatomic, retain) RMAnnotation *selectedAnnotation;
  347 +
333 #pragma mark - TileSources 348 #pragma mark - TileSources
334 349
335 @property (nonatomic, retain) RMQuadTree *quadTree; 350 @property (nonatomic, retain) RMQuadTree *quadTree;
@@ -1511,19 +1511,7 @@ @@ -1511,19 +1511,7 @@
1511 1511
1512 if (_currentAnnotation && ! [hit isEqual:_currentAnnotation.layer]) 1512 if (_currentAnnotation && ! [hit isEqual:_currentAnnotation.layer])
1513 { 1513 {
1514 - [self correctPositionOfAllAnnotations];  
1515 -  
1516 - BOOL animated = ( ! [hit isKindOfClass:[RMMarker class]]);  
1517 -  
1518 - [_currentCallout dismissCalloutAnimated:animated];  
1519 -  
1520 - if (animated)  
1521 - [self performSelector:@selector(correctPositionOfAllAnnotations) withObject:nil afterDelay:1.0/3.0];  
1522 - else  
1523 - [self correctPositionOfAllAnnotations];  
1524 -  
1525 - [_currentAnnotation release]; _currentAnnotation = nil;  
1526 - [_currentCallout release]; _currentCallout = nil; 1514 + [self deselectAnnotation:_currentAnnotation animated:( ! [hit isKindOfClass:[RMMarker class]])];
1527 } 1515 }
1528 1516
1529 if ( ! hit) 1517 if ( ! hit)
@@ -1699,33 +1687,8 @@ @@ -1699,33 +1687,8 @@
1699 1687
1700 - (void)tapOnAnnotation:(RMAnnotation *)anAnnotation atPoint:(CGPoint)aPoint 1688 - (void)tapOnAnnotation:(RMAnnotation *)anAnnotation atPoint:(CGPoint)aPoint
1701 { 1689 {
1702 - if (anAnnotation.layer && anAnnotation.layer.canShowCallout && anAnnotation.title && ! [anAnnotation isEqual:_currentAnnotation])  
1703 - {  
1704 - _currentAnnotation = [anAnnotation retain];  
1705 -  
1706 - _currentCallout = [SMCalloutView new];  
1707 -  
1708 - _currentCallout.title = anAnnotation.title;  
1709 - _currentCallout.subtitle = anAnnotation.subtitle;  
1710 -  
1711 - if (anAnnotation.layer.leftCalloutAccessoryView)  
1712 - {  
1713 - if ([anAnnotation.layer.leftCalloutAccessoryView isKindOfClass:[UIControl class]])  
1714 - [anAnnotation.layer.leftCalloutAccessoryView addGestureRecognizer:[[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapOnCalloutAccessoryWithGestureRecognizer:)] autorelease]];  
1715 -  
1716 - _currentCallout.leftAccessoryView = anAnnotation.layer.leftCalloutAccessoryView;  
1717 - }  
1718 -  
1719 - if (anAnnotation.layer.rightCalloutAccessoryView) 1690 + if (anAnnotation.layer && anAnnotation.isAnnotationOnScreen && anAnnotation.layer.canShowCallout && anAnnotation.title && ! [anAnnotation isEqual:_currentAnnotation])
1720 { 1691 {
1721 - if ([anAnnotation.layer.rightCalloutAccessoryView isKindOfClass:[UIControl class]])  
1722 - [anAnnotation.layer.rightCalloutAccessoryView addGestureRecognizer:[[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapOnCalloutAccessoryWithGestureRecognizer:)] autorelease]];  
1723 -  
1724 - _currentCallout.rightAccessoryView = anAnnotation.layer.rightCalloutAccessoryView;  
1725 - }  
1726 -  
1727 - _currentCallout.delegate = self;  
1728 -  
1729 [self performSelector:@selector(popupCalloutViewForAnnotation:) withObject:anAnnotation afterDelay:1.0/3.0]; // allows for MapKit-like delay 1692 [self performSelector:@selector(popupCalloutViewForAnnotation:) withObject:anAnnotation afterDelay:1.0/3.0]; // allows for MapKit-like delay
1730 } 1693 }
1731 1694
@@ -1753,8 +1716,74 @@ @@ -1753,8 +1716,74 @@
1753 return [super hitTest:point withEvent:event]; 1716 return [super hitTest:point withEvent:event];
1754 } 1717 }
1755 1718
  1719 +- (void)selectAnnotation:(RMAnnotation *)annotation animated:(BOOL)animated
  1720 +{
  1721 + if (annotation.isAnnotationOnScreen && ! [annotation isEqual:_currentAnnotation])
  1722 + {
  1723 + [self deselectAnnotation:_currentAnnotation animated:NO];
  1724 + [self popupCalloutViewForAnnotation:annotation animated:animated];
  1725 + }
  1726 +}
  1727 +
  1728 +- (void)deselectAnnotation:(RMAnnotation *)annotation animated:(BOOL)animated
  1729 +{
  1730 + if ([annotation isEqual:_currentAnnotation] && _currentCallout)
  1731 + {
  1732 + [_currentCallout dismissCalloutAnimated:animated];
  1733 +
  1734 + if (animated)
  1735 + [self performSelector:@selector(correctPositionOfAllAnnotations) withObject:nil afterDelay:1.0/3.0];
  1736 + else
  1737 + [self correctPositionOfAllAnnotations];
  1738 +
  1739 + [_currentAnnotation release]; _currentAnnotation = nil;
  1740 + [_currentCallout release]; _currentCallout = nil;
  1741 + }
  1742 +}
  1743 +
  1744 +- (void)setSelectedAnnotation:(RMAnnotation *)selectedAnnotation
  1745 +{
  1746 + if ( ! [selectedAnnotation isEqual:_currentAnnotation])
  1747 + [self selectAnnotation:selectedAnnotation animated:YES];
  1748 +}
  1749 +
  1750 +- (RMAnnotation *)selectedAnnotation
  1751 +{
  1752 + return _currentAnnotation;
  1753 +}
  1754 +
1756 - (void)popupCalloutViewForAnnotation:(RMAnnotation *)anAnnotation 1755 - (void)popupCalloutViewForAnnotation:(RMAnnotation *)anAnnotation
1757 { 1756 {
  1757 + [self popupCalloutViewForAnnotation:anAnnotation animated:YES];
  1758 +}
  1759 +
  1760 +- (void)popupCalloutViewForAnnotation:(RMAnnotation *)anAnnotation animated:(BOOL)animated
  1761 +{
  1762 + _currentAnnotation = [anAnnotation retain];
  1763 +
  1764 + _currentCallout = [SMCalloutView new];
  1765 +
  1766 + _currentCallout.title = anAnnotation.title;
  1767 + _currentCallout.subtitle = anAnnotation.subtitle;
  1768 +
  1769 + if (anAnnotation.layer.leftCalloutAccessoryView)
  1770 + {
  1771 + if ([anAnnotation.layer.leftCalloutAccessoryView isKindOfClass:[UIControl class]])
  1772 + [anAnnotation.layer.leftCalloutAccessoryView addGestureRecognizer:[[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapOnCalloutAccessoryWithGestureRecognizer:)] autorelease]];
  1773 +
  1774 + _currentCallout.leftAccessoryView = anAnnotation.layer.leftCalloutAccessoryView;
  1775 + }
  1776 +
  1777 + if (anAnnotation.layer.rightCalloutAccessoryView)
  1778 + {
  1779 + if ([anAnnotation.layer.rightCalloutAccessoryView isKindOfClass:[UIControl class]])
  1780 + [anAnnotation.layer.rightCalloutAccessoryView addGestureRecognizer:[[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapOnCalloutAccessoryWithGestureRecognizer:)] autorelease]];
  1781 +
  1782 + _currentCallout.rightAccessoryView = anAnnotation.layer.rightCalloutAccessoryView;
  1783 + }
  1784 +
  1785 + _currentCallout.delegate = self;
  1786 +
1758 [self correctPositionOfAllAnnotations]; 1787 [self correctPositionOfAllAnnotations];
1759 1788
1760 anAnnotation.layer.zPosition = _currentCallout.layer.zPosition = MAXFLOAT; 1789 anAnnotation.layer.zPosition = _currentCallout.layer.zPosition = MAXFLOAT;
@@ -1763,7 +1792,7 @@ @@ -1763,7 +1792,7 @@
1763 inLayer:anAnnotation.layer 1792 inLayer:anAnnotation.layer
1764 constrainedToLayer:self.layer 1793 constrainedToLayer:self.layer
1765 permittedArrowDirections:SMCalloutArrowDirectionDown 1794 permittedArrowDirections:SMCalloutArrowDirectionDown
1766 - animated:YES]; 1795 + animated:animated];
1767 } 1796 }
1768 1797
1769 - (NSTimeInterval)calloutView:(SMCalloutView *)calloutView delayForRepositionWithSize:(CGSize)offset 1798 - (NSTimeInterval)calloutView:(SMCalloutView *)calloutView delayForRepositionWithSize:(CGSize)offset
1 -Subproject commit 19b961aba04a136bbc18906b7cb5e60a6fa61888 1 +Subproject commit 2e7435a5449fa9c440d11206f7bfc40da3f8fe97