2021-08-05 00:02:35 +02:00

329 lines
9.8 KiB
Objective-C

#import "TGTooltipView.h"
#import "LegacyComponentsInternal.h"
#import "TGFont.h"
#import "TGImageUtils.h"
#import <QuartzCore/QuartzCore.h>
@interface TGTooltipView () <UIScrollViewDelegate>
{
UIImageView *_backgroundView;
UIImageView *_arrowView;
UILabel *_textLabel;
CGFloat _arrowLocation;
}
@property (nonatomic, strong) ASHandle *watcherHandle;
@end
@implementation TGTooltipView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.alpha = 0.0f;
self.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
_numberOfLines = 1;
_maxWidth = 320.0f;
_backgroundView = [[UIImageView alloc] initWithImage:[TGTintedImage(TGComponentsImageNamed(@"TooltipBackground"), UIColorRGBA(0x252525, 0.96f)) stretchableImageWithLeftCapWidth:9.0f topCapHeight:9.0f]];
[self addSubview:_backgroundView];
_arrowView = [[UIImageView alloc] initWithImage:TGTintedImage(TGComponentsImageNamed(@"TooltipArrow"), UIColorRGBA(0x252525, 0.96f))];
[self addSubview:_arrowView];
_arrowLocation = 50;
}
return self;
}
- (void)setForceArrowOnTop:(bool)forceArrowOnTop
{
_forceArrowOnTop = forceArrowOnTop;
_arrowView.image = [UIImage imageWithCGImage:_arrowView.image.CGImage scale:_arrowView.image.scale orientation:UIImageOrientationDown];
}
- (void)setText:(NSString *)text
{
[self setText:text animated:false];
}
- (void)setText:(NSString *)text animated:(bool)animated
{
if (_textLabel == nil)
{
_textLabel = [[UILabel alloc] init];
_textLabel.backgroundColor = [UIColor clearColor];
_textLabel.font = TGSystemFontOfSize(14);
_textLabel.textColor = [UIColor whiteColor];
_textLabel.userInteractionEnabled = false;
_textLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:_textLabel];
}
_textLabel.numberOfLines = _numberOfLines;
if (animated)
{
[UIView transitionWithView:_textLabel duration:0.2 options:UIViewAnimationOptionTransitionCrossDissolve animations:^
{
_textLabel.text = text;
} completion:nil];
[UIView animateWithDuration:0.2 animations:^
{
[self sizeToFit];
} completion:^(__unused BOOL finished)
{
}];
}
else
{
_textLabel.text = text;
if (_numberOfLines == 1) {
[_textLabel sizeToFit];
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
CGSize textSize = [_textLabel.text sizeWithFont:_textLabel.font constrainedToSize:CGSizeMake(_maxWidth - 20.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
#pragma clang diagnostic pop
textSize.width = CGCeil(textSize.width);
textSize.height = CGCeil(textSize.height);
_textLabel.frame = CGRectMake(_textLabel.frame.origin.x, _textLabel.frame.origin.y, textSize.width, textSize.height);
}
}
}
- (void)sizeToFit
{
CGAffineTransform transform = self.transform;
self.transform = CGAffineTransformIdentity;
CGFloat maxWidth = _maxWidth;
CGFloat inset = 9.0f;
if (_numberOfLines == 1) {
[_textLabel sizeToFit];
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
CGSize textSize = [_textLabel.text sizeWithFont:_textLabel.font constrainedToSize:CGSizeMake(maxWidth - 20.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
#pragma clang diagnostic pop
textSize.width = CGCeil(textSize.width);
textSize.height = CGCeil(textSize.height);
_textLabel.frame = CGRectMake(_textLabel.frame.origin.x, _textLabel.frame.origin.y, textSize.width, textSize.height);
}
CGFloat minArrowX = 10.0f;
CGFloat maxArrowX = self.frame.size.width - 10.0f;
CGFloat arrowX = CGFloor(_arrowLocation - _arrowView.frame.size.width / 2);
arrowX = MIN(MAX(minArrowX, arrowX), maxArrowX);
_arrowView.frame = CGRectMake(arrowX + TGScreenPixel, _forceArrowOnTop ? 0.0f : 38.0f - TGScreenPixel, _arrowView.frame.size.width, _arrowView.frame.size.height);
CGFloat backgroundOffset = 19.0f + _textLabel.frame.size.height - 36.0f;
CGFloat backgroundWidth = MIN(maxWidth, _textLabel.frame.size.width + inset * 2.0f);
CGFloat labelWidth = backgroundWidth - inset * 2.0f;
if (_numberOfLines != 1) {
labelWidth = _textLabel.frame.size.width;
backgroundOffset += 1.0f;
}
CGFloat x = arrowX - (backgroundWidth - _arrowView.frame.size.width) / 2.0f;
x = MAX(4.0f, MIN(x, self.frame.size.width - backgroundWidth - 4.0f));
_backgroundView.frame = CGRectMake(x, 2.0f - backgroundOffset + (_forceArrowOnTop ? 7.0f : 0.0f), backgroundWidth, 36.0f + backgroundOffset);
_textLabel.frame = CGRectMake(_backgroundView.frame.origin.x + inset, 12.0f - TGScreenPixel - backgroundOffset + (_forceArrowOnTop ? 7.0f : 0.0f), labelWidth, _textLabel.frame.size.height);
if (_forceArrowOnTop)
{
_arrowView.frame = CGRectMake(_arrowView.frame.origin.x, _backgroundView.frame.origin.y - _arrowView.frame.size.height, _arrowView.frame.size.width, _arrowView.frame.size.height);
}
self.transform = transform;
}
- (void)showInView:(UIView *)view fromRect:(CGRect)rect
{
[self showInView:view fromRect:rect animated:true];
}
- (void)showInView:(UIView *)__unused view fromRect:(CGRect)rect animated:(bool)animated
{
CGAffineTransform transform = self.transform;
self.transform = CGAffineTransformIdentity;
CGRect frame = self.frame;
if (_forceArrowOnTop)
frame.origin.y = rect.origin.y + 24.0f;
else
frame.origin.y = rect.origin.y - frame.size.height - 14.0f;
_arrowLocation = CGFloor(rect.origin.x + rect.size.width / 2) - frame.origin.x;
self.frame = frame;
[self sizeToFit];
self.transform = transform;
self.layer.rasterizationScale = [[UIScreen mainScreen] scale];
self.layer.shouldRasterize = true;
self.alpha = 1.0f;
if (animated)
{
[UIView animateWithDuration:0.142 delay:0 options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState animations:^
{
self.transform = CGAffineTransformMakeScale(1.07f, 1.07f);
} completion:^(BOOL finished)
{
if(finished)
{
[UIView animateWithDuration:0.08 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
{
self.transform = CGAffineTransformMakeScale(0.967f, 0.967f);
} completion:^(BOOL finished)
{
if (finished)
{
[UIView animateWithDuration:0.06 delay:0 options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState animations:^
{
self.transform = CGAffineTransformIdentity;
} completion:^(BOOL finished)
{
if (finished)
{
self.layer.shouldRasterize = false;
}
}];
}
}];
}
}];
}
else
{
self.transform = CGAffineTransformIdentity;
self.alpha = 0.0f;
[UIView animateWithDuration:0.3 animations:^
{
self.alpha = 1.0f;
}];
}
}
- (void)hide:(dispatch_block_t)completion
{
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
{
self.alpha = 0.0f;
} completion:^(BOOL finished)
{
if (finished)
{
self.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
if (completion)
completion();
}
}];
}
@end
#pragma mark -
@interface TGTooltipContainerView ()
{
bool _skipHitTest;
}
@end
@implementation TGTooltipContainerView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self != nil)
{
_tooltipView = [[TGTooltipView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, frame.size.width, 41.0f)];
[self addSubview:_tooltipView];
}
return self;
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (_skipHitTest)
return nil;
UIView *result = [super hitTest:point withEvent:event];
UIView *superViewResult = nil;
if (self.tooltipView.sourceView != nil)
{
_skipHitTest = true;
superViewResult = [self.superview hitTest:[self convertPoint:point toView:self.superview] withEvent:event];
_skipHitTest = false;
}
if (self.tooltipView.sourceView != nil && superViewResult == self.tooltipView.sourceView)
return nil;
if (result == self || result == nil)
{
[self hideTooltip];
return nil;
}
return result;
}
- (void)showTooltipFromRect:(CGRect)rect
{
[self showTooltipFromRect:rect animated:true];
}
- (void)showTooltipFromRect:(CGRect)rect animated:(bool)animated
{
_isShowingTooltip = true;
_showingTooltipFromRect = rect;
[_tooltipView showInView:self fromRect:rect animated:animated];
}
- (void)setFrame:(CGRect)frame
{
if (!CGSizeEqualToSize(frame.size, self.frame.size))
[self hideTooltip];
[super setFrame:frame];
}
- (void)hideTooltip
{
if (_isShowingTooltip)
{
_isShowingTooltip = false;
_showingTooltipFromRect = CGRectZero;
[_tooltipView.watcherHandle requestAction:@"tooltipWillHide" options:nil];
[_tooltipView hide:^
{
[self removeFromSuperview];
}];
}
}
@end