1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-02 09:27:55 +01:00
Telegram/Telegraph/TGPhotoCropAreaView.m
2015-10-01 19:19:52 +03:00

500 lines
21 KiB
Objective-C

#import "TGPhotoCropAreaView.h"
#import "TGPhotoCropGridView.h"
#import "UIControl+HitTestEdgeInsets.h"
#import "TGPhotoCropControl.h"
const CGSize TGPhotoCropCornerControlSize = { 44, 44 };
const CGFloat TGPhotoCropEdgeControlSize = 44;
@interface TGPhotoCropAreaView ()
{
bool _isTracking;
UIImageView *_cornersView;
UIView *_topEdgeHighlight;
UIView *_leftEdgeHighlight;
UIView *_rightEdgeHighlight;
UIView *_bottomEdgeHighlight;
TGPhotoCropControl *_topLeftCornerControl;
TGPhotoCropControl *_topRightCornerControl;
TGPhotoCropControl *_bottomLeftCornerControl;
TGPhotoCropControl *_bottomRightCornerControl;
TGPhotoCropControl *_topEdgeControl;
TGPhotoCropControl *_leftEdgeControl;
TGPhotoCropControl *_bottomEdgeControl;
TGPhotoCropControl *_rightEdgeControl;
TGPhotoCropGridView *_majorGridView;
TGPhotoCropGridView *_minorGridView;
}
@property (nonatomic, copy) bool(^shouldBeginResizing)(TGPhotoCropControl *sender);
@property (nonatomic, copy) void(^didBeginResizing)(TGPhotoCropControl *sender);
@property (nonatomic, copy) void(^didResize)(TGPhotoCropControl *sender, CGPoint translation);
@property (nonatomic, copy) void(^didEndResizing)(TGPhotoCropControl *sender);
@end
@implementation TGPhotoCropAreaView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self != nil)
{
__weak TGPhotoCropAreaView *weakSelf = self;
self.shouldBeginResizing = ^bool(__unused TGPhotoCropControl *sender)
{
__strong TGPhotoCropAreaView *strongSelf = weakSelf;
if (strongSelf != nil)
{
if (strongSelf.shouldBeginEditing != nil)
return strongSelf.shouldBeginEditing();
}
return true;
};
self.didBeginResizing = ^(__unused TGPhotoCropControl *sender)
{
__strong TGPhotoCropAreaView *strongSelf = weakSelf;
if (strongSelf == nil)
return;
strongSelf->_isTracking = true;
if (strongSelf.didBeginEditing != nil)
strongSelf.didBeginEditing();
if (strongSelf->_lockAspectRatio)
return;
if (sender == strongSelf->_topEdgeControl)
strongSelf->_topEdgeHighlight.hidden = false;
else if (sender == strongSelf->_leftEdgeControl)
strongSelf->_leftEdgeHighlight.hidden = false;
else if (sender == strongSelf->_bottomEdgeControl)
strongSelf->_bottomEdgeHighlight.hidden = false;
else if (sender == strongSelf->_rightEdgeControl)
strongSelf->_rightEdgeHighlight.hidden = false;
};
self.didResize = ^(TGPhotoCropControl *sender, CGPoint translation)
{
__strong TGPhotoCropAreaView *strongSelf = weakSelf;
if (strongSelf == nil)
return;
[strongSelf handleResizeWithSender:sender translation:translation];
if (strongSelf.areaChanged != nil)
strongSelf.areaChanged();
};
self.didEndResizing = ^(TGPhotoCropControl *sender)
{
__strong TGPhotoCropAreaView *strongSelf = weakSelf;
if (strongSelf == nil)
return;
strongSelf->_isTracking = false;
if (strongSelf.didEndEditing != nil)
strongSelf.didEndEditing();
if (strongSelf->_lockAspectRatio)
return;
if (sender == strongSelf->_topEdgeControl)
strongSelf->_topEdgeHighlight.hidden = true;
else if (sender == strongSelf->_leftEdgeControl)
strongSelf->_leftEdgeHighlight.hidden = true;
else if (sender == strongSelf->_bottomEdgeControl)
strongSelf->_bottomEdgeHighlight.hidden = true;
else if (sender == strongSelf->_rightEdgeControl)
strongSelf->_rightEdgeHighlight.hidden = true;
};
self.hitTestEdgeInsets = UIEdgeInsetsMake(-16, -16, -16, -16);
_cornersView = [[UIImageView alloc] initWithFrame:CGRectInset(self.bounds, -2, -2)];
_cornersView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_cornersView.image = [[UIImage imageNamed:@"PhotoEditorCropCorners"] resizableImageWithCapInsets:UIEdgeInsetsMake(20, 20, 20, 20)];
[self addSubview:_cornersView];
_topEdgeHighlight = [[UIView alloc] initWithFrame:CGRectMake(0, -1, frame.size.width, 2)];
_topEdgeHighlight.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_topEdgeHighlight.backgroundColor = [UIColor whiteColor];
_topEdgeHighlight.hidden = true;
[self addSubview:_topEdgeHighlight];
_leftEdgeHighlight = [[UIView alloc] initWithFrame:CGRectMake(-1, 0, 2, frame.size.height)];
_leftEdgeHighlight.autoresizingMask = UIViewAutoresizingFlexibleHeight;
_leftEdgeHighlight.backgroundColor = [UIColor whiteColor];
_leftEdgeHighlight.hidden = true;
[self addSubview:_leftEdgeHighlight];
_rightEdgeHighlight = [[UIView alloc] initWithFrame:CGRectMake(frame.size.width - 1, 0, 2, frame.size.height)];
_rightEdgeHighlight.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
_rightEdgeHighlight.backgroundColor = [UIColor whiteColor];
_rightEdgeHighlight.hidden = true;
[self addSubview:_rightEdgeHighlight];
_bottomEdgeHighlight = [[UIView alloc] initWithFrame:CGRectMake(0, frame.size.height - 1, frame.size.width, 2)];
_bottomEdgeHighlight.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
_bottomEdgeHighlight.backgroundColor = [UIColor whiteColor];
_bottomEdgeHighlight.hidden = true;
[self addSubview:_bottomEdgeHighlight];
_topEdgeControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(TGPhotoCropCornerControlSize.width / 2,
-TGPhotoCropEdgeControlSize / 2,
frame.size.width - TGPhotoCropCornerControlSize.width,
TGPhotoCropEdgeControlSize)];
_topEdgeControl.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_topEdgeControl.hitTestEdgeInsets = UIEdgeInsetsMake(-16, 0, -16, 0);
[self addSubview:_topEdgeControl];
_leftEdgeControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(-TGPhotoCropEdgeControlSize / 2,
TGPhotoCropCornerControlSize.height / 2,
TGPhotoCropEdgeControlSize,
frame.size.height - TGPhotoCropCornerControlSize.height)];
_leftEdgeControl.autoresizingMask = UIViewAutoresizingFlexibleHeight;
_leftEdgeControl.hitTestEdgeInsets = UIEdgeInsetsMake(0, -16, 0, -16);
[self addSubview:_leftEdgeControl];
_bottomEdgeControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(TGPhotoCropCornerControlSize.width / 2,
frame.size.height - TGPhotoCropEdgeControlSize / 2,
frame.size.width - TGPhotoCropCornerControlSize.width,
TGPhotoCropEdgeControlSize)];
_bottomEdgeControl.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
_bottomEdgeControl.hitTestEdgeInsets = UIEdgeInsetsMake(-16, 0, -16, 0);
[self addSubview:_bottomEdgeControl];
_rightEdgeControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(frame.size.width - TGPhotoCropEdgeControlSize / 2,
TGPhotoCropCornerControlSize.height / 2,
TGPhotoCropEdgeControlSize,
frame.size.height - TGPhotoCropCornerControlSize.height)];
_rightEdgeControl.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
_rightEdgeControl.hitTestEdgeInsets = UIEdgeInsetsMake(0, -16, 0, -16);
[self addSubview:_rightEdgeControl];
_topLeftCornerControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(-TGPhotoCropCornerControlSize.width / 2,
-TGPhotoCropCornerControlSize.height / 2,
TGPhotoCropCornerControlSize.width,
TGPhotoCropCornerControlSize.height)];
_topLeftCornerControl.hitTestEdgeInsets = UIEdgeInsetsMake(-16, -16, -16, -16);
[self addSubview:_topLeftCornerControl];
_topRightCornerControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(frame.size.width - TGPhotoCropCornerControlSize.width / 2,
-TGPhotoCropCornerControlSize.height / 2,
TGPhotoCropCornerControlSize.width,
TGPhotoCropCornerControlSize.height)];
_topRightCornerControl.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
_topRightCornerControl.hitTestEdgeInsets = UIEdgeInsetsMake(-16, -16, -16, -16);
[self addSubview:_topRightCornerControl];
_bottomLeftCornerControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(-TGPhotoCropCornerControlSize.width / 2,
frame.size.height - TGPhotoCropCornerControlSize.height / 2,
TGPhotoCropCornerControlSize.width,
TGPhotoCropCornerControlSize.height)];
_bottomLeftCornerControl.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
_bottomLeftCornerControl.hitTestEdgeInsets = UIEdgeInsetsMake(-16, -16, -16, -16);
[self addSubview:_bottomLeftCornerControl];
_bottomRightCornerControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(frame.size.width - TGPhotoCropCornerControlSize.width / 2,
frame.size.height - TGPhotoCropCornerControlSize.height / 2,
TGPhotoCropCornerControlSize.width,
TGPhotoCropCornerControlSize.height)];
_bottomRightCornerControl.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
_bottomRightCornerControl.hitTestEdgeInsets = UIEdgeInsetsMake(-16, -16, -16, -16);
[self addSubview:_bottomRightCornerControl];
for (UIView *view in self.subviews)
{
if ([view isKindOfClass:[TGPhotoCropControl class]])
{
TGPhotoCropControl *control = (TGPhotoCropControl *)view;
control.shouldBeginResizing = self.shouldBeginResizing;
control.didBeginResizing = self.didBeginResizing;
control.didResize = self.didResize;
control.didEndResizing = self.didEndResizing;
}
}
_majorGridView = [[TGPhotoCropGridView alloc] initWithMode:TGPhotoCropViewGridModeMajor];
_majorGridView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_majorGridView.frame = self.bounds;
_majorGridView.hidden = true;
[self addSubview:_majorGridView];
_minorGridView = [[TGPhotoCropGridView alloc] initWithMode:TGPhotoCropViewGridModeMinor];
_minorGridView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_minorGridView.frame = self.bounds;
_minorGridView.hidden = true;
[self addSubview:_minorGridView];
}
return self;
}
- (bool)isTracking
{
return _isTracking;
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)__unused event
{
UIView *view = [super hitTest:point withEvent:event];
if ([view isKindOfClass:[TGPhotoCropControl class]])
return view;
return nil;
}
#pragma mark - Aspect Ratio
- (void)setAspectRatio:(CGFloat)aspectRatio
{
_aspectRatio = aspectRatio;
}
- (void)setLockAspectRatio:(bool)lockAspectRatio
{
_lockAspectRatio = lockAspectRatio;
_topEdgeHighlight.hidden = !lockAspectRatio;
_leftEdgeHighlight.hidden = !lockAspectRatio;
_rightEdgeHighlight.hidden = !lockAspectRatio;
_bottomEdgeHighlight.hidden = !lockAspectRatio;
}
#pragma mark - Grid
- (void)setGridMode:(TGPhotoCropViewGridMode)mode
{
[self setGridMode:mode animated:false];
}
- (void)setGridMode:(TGPhotoCropViewGridMode)gridMode animated:(bool)animated
{
if (_gridMode == gridMode)
return;
_gridMode = gridMode;
switch (gridMode)
{
case TGPhotoCropViewGridModeMajor:
{
[self setGridView:_majorGridView hidden:false animated:animated];
[self setGridView:_minorGridView hidden:true animated:animated];
}
break;
case TGPhotoCropViewGridModeMinor:
{
[self setGridView:_majorGridView hidden:true animated:animated];
[self setGridView:_minorGridView hidden:false animated:animated];
}
break;
default:
{
[self setGridView:_majorGridView hidden:true animated:animated];
[self setGridView:_minorGridView hidden:true animated:animated];
}
break;
}
}
- (void)setGridView:(TGPhotoCropGridView *)gridView hidden:(bool)hidden animated:(bool)animated
{
if (animated)
[gridView setHidden:hidden animated:true duration:0.2f delay:0.0f];
else
gridView.hidden = hidden;
}
#pragma mark - Resize
- (void)handleResizeWithSender:(TGPhotoCropControl *)sender translation:(CGPoint)translation
{
CGRect rect = self.frame;
if (sender == _topLeftCornerControl)
{
rect = CGRectMake(self.frame.origin.x + translation.x,
self.frame.origin.y + translation.y,
self.frame.size.width - translation.x,
self.frame.size.height - translation.y);
if (self.lockAspectRatio)
{
CGRect constrainedRect = [self constrainedRectFromRectWithWidth:rect aspectRatio:self.aspectRatio];
if (ABS(translation.x) < ABS(translation.y))
constrainedRect = [self constrainedRectFromRectWithHeight:rect aspectRatio:self.aspectRatio];
constrainedRect.origin.x -= constrainedRect.size.width - rect.size.width;
constrainedRect.origin.y -= constrainedRect.size.height - rect.size.height;
rect = constrainedRect;
}
}
else if (sender == _topRightCornerControl)
{
rect = CGRectMake(self.frame.origin.x,
self.frame.origin.y + translation.y,
self.frame.size.width + translation.x,
self.frame.size.height - translation.y);
if (self.lockAspectRatio)
{
CGRect constrainedRect = [self constrainedRectFromRectWithWidth:rect aspectRatio:self.aspectRatio];
if (ABS(translation.x) < ABS(translation.y))
constrainedRect = [self constrainedRectFromRectWithHeight:rect aspectRatio:self.aspectRatio];
constrainedRect.origin.y -= constrainedRect.size.height - rect.size.height;
rect = constrainedRect;
}
}
else if (sender == _bottomLeftCornerControl)
{
rect = CGRectMake(self.frame.origin.x + translation.x,
self.frame.origin.y,
self.frame.size.width - translation.x,
self.frame.size.height + translation.y);
if (self.lockAspectRatio)
{
CGRect constrainedRect;
if (ABS(translation.x) < ABS(translation.y))
constrainedRect = [self constrainedRectFromRectWithHeight:rect aspectRatio:self.aspectRatio];
else
constrainedRect = [self constrainedRectFromRectWithWidth:rect aspectRatio:self.aspectRatio];
constrainedRect.origin.x -= constrainedRect.size.width - rect.size.width;
rect = constrainedRect;
}
}
else if (sender == _bottomRightCornerControl)
{
rect = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
self.frame.size.width + translation.x,
self.frame.size.height + translation.y);
if (self.lockAspectRatio)
{
if (ABS(translation.x) < ABS(translation.y))
rect = [self constrainedRectFromRectWithHeight:rect aspectRatio:self.aspectRatio];
else
rect = [self constrainedRectFromRectWithWidth:rect aspectRatio:self.aspectRatio];
}
}
else if (sender == _topEdgeControl)
{
rect = CGRectMake(self.frame.origin.x,
self.frame.origin.y + translation.y,
self.frame.size.width,
self.frame.size.height - translation.y);
if (self.lockAspectRatio)
rect = [self constrainedRectFromRectWithHeight:rect aspectRatio:self.aspectRatio];
}
else if (sender == _leftEdgeControl)
{
rect = CGRectMake(self.frame.origin.x + translation.x,
self.frame.origin.y,
self.frame.size.width - translation.x,
self.frame.size.height);
if (self.lockAspectRatio)
rect = [self constrainedRectFromRectWithWidth:rect aspectRatio:self.aspectRatio];
}
else if (sender == _bottomEdgeControl)
{
rect = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
self.frame.size.width,
self.frame.size.height + translation.y);
if (self.lockAspectRatio)
rect = [self constrainedRectFromRectWithHeight:rect aspectRatio:self.aspectRatio];
}
else if (sender == _rightEdgeControl)
{
rect = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
self.frame.size.width + translation.x,
self.frame.size.height);
if (self.lockAspectRatio)
rect = [self constrainedRectFromRectWithWidth:rect aspectRatio:self.aspectRatio];
}
CGFloat minimumWidth = TGPhotoCropCornerControlSize.width;
if (rect.size.width < minimumWidth)
rect.size.width = minimumWidth;
CGFloat minimumHeight = TGPhotoCropCornerControlSize.height;
if (rect.size.height < minimumHeight)
rect.size.height = minimumHeight;
if (self.lockAspectRatio)
{
CGRect constrainedRect = rect;
if (self.aspectRatio > 1)
{
if (rect.size.width <= minimumWidth)
{
constrainedRect.size.width = minimumWidth;
constrainedRect.size.height = constrainedRect.size.width * self.aspectRatio;
}
}
else
{
if (rect.size.height <= minimumHeight)
{
constrainedRect.size.height = minimumHeight;
constrainedRect.size.width = constrainedRect.size.height / self.aspectRatio;
}
}
rect = constrainedRect;
}
self.frame = rect;
}
- (CGRect)constrainedRectFromRectWithWidth:(CGRect)rect aspectRatio:(CGFloat)aspectRatio
{
CGFloat width = rect.size.width;
CGFloat height = width * aspectRatio;
rect.size = CGSizeMake(width, height);
return rect;
}
- (CGRect)constrainedRectFromRectWithHeight:(CGRect)rect aspectRatio:(CGFloat)aspectRatio
{
CGFloat height = rect.size.height;
CGFloat width = height / aspectRatio;
rect.size = CGSizeMake(width, height);
return rect;
}
@end